匈牙利算法+HDU2063

匈牙利算法
例题1:HDU2063
题目:
RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?
输入:
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
输出:
对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。
样例输入:
6 3 3
1 1
1 2
1 3
2 1
2 3
3 1
0
样例输出:
3
算法解析:他人匈牙利算法借鉴``
HDU2063:

#include<stdio.h>
#include<string.h>
int line[1001][1001];//line[x][y]:x号女和y号男可以相互接受 
int used[1001];//方便递推的时候,进行记录(3号找不到女生,就跟一号女生,一号男生就跟二号女生此时used[]==1;二号男生找到一号,二号女生都名花有主了) 
int partner[1001];//partner[x]=y;x号女对应着y号男 
int w,m;
int findpartner(int x);
int main(){
	int k;
	while(~scanf("%d",&k)&&k){
		getchar();
		int sum=0;
		scanf("%d %d",&w,&m);
		getchar();
		memset(line,0,sizeof(line));
		memset(partner,0,sizeof(partner));//memset,将数组初始化,只能是0或者世-1:哈哈哈 
		for(int i=0;i<k;i++){
			int a,b;
			scanf("%d %d",&a,&b);
			line[a][b]=1;//a,b之间有意愿; 
		}
		for(int i=1;i<=w;i++){
			memset(used,0,sizeof(used));
			if(findpartner(i))
			sum++;
		}
		printf("%d\n",sum);	
	}
	
	return 0;
}
int findpartner(int x){
	for(int i=1;i<=m;i++){
		if(used[i]==0&&line[x][i]==1){
			used[i]=1;
			if(partner[i]==0||findpartner(partner[i])==1){
				partner[i]=x;
				return 1;
			} 
		}
	}
	return 0;
}

例题2:
N个人分配N项任务,一个人只能分配一项任务,一项任务只能分配给一个人,将一项任务分配给一个人是需要支付报酬,如何分配任务,保证支付的报酬总数最小。
解:方法一:实例分析—穷举法
以3个工作人员和3项任务为实例,下图为薪酬图表和根据薪酬图表所得的cost矩阵。

  
利用最简单的方法(穷举法)进行求解,计算出所有分配情况的总薪酬开销,然后求最小值。
total_cost1 = 250 + 600 + 250 = 1100; x00 = 1,x11 = 1,x22 = 1;
total_cost2 = 250 + 350 + 400 = 1000; x00 = 1,x12 = 1,x21 = 1;
total_cost3 = 400 + 400 + 250 = 1050; x01 = 1,x10 = 1,x22 = 1;
total_cost4 = 400 + 350 + 200 = 950; x01 = 1,x12 = 1,x20 = 1; //最优分配
total_cost5 = 350 + 400 + 400 = 1150; x02 = 1,x10 = 1,x21 = 1;
total_cost6 = 350 + 600 + 250 = 1150; x02 = 1,x11 = 1,x22 = 1;
对于任务数和人员数较少时,可利用穷举法计算结果。
若将N任务分配给N个人员,其包含的所有分配情况数目为N!,N增大时,穷举法将难以完成任务。
方法二:匈牙利算法:
其基本的理论基础是针对cost矩阵,将cost矩阵的一行或一列数据加上或减去一个数,其最优任务分配求解问题不变。(cost矩阵:效益矩阵)
在这里插入图片描述
【可以去学一下运筹学的知识】
第一步,变换效益矩阵 C ,使每行每列中都有数 0 .每行元素减去本行中最小元素(称为按行减), 每列元
素减去该列中最小元素(称为按列减), 这样就可使每行每列中都有 0 .称所得矩阵为缩减矩阵.
第二步,作出能覆盖所有数 0 的最少水平或竖直的直线.若直线的条数小于方阵 C 的n ,则转入下一步,否则执行第四步 .
第三步 ,进行增 0 变换.在没有被直线覆盖的元素中找出最小元素 ,然后将所有未被直线覆盖的元素减去此最小元素, 所有被二条直线覆盖的交叉处的元素加上此最小元素 ,其余元素不变 .得新的缩减矩阵.返回第二步.
第四步 ,确定缩减矩阵中 n 个独立 0 的位置.对行中只有一个 0 的位置打上“ *” , 同时划去该 0 所在列的其余的0 ;再逐列检查 ,对列中只有一个0 的位置打上“ *” ,同时划去该0 所在行中的其余的0 .如果遇到每行(列)有两个或两个以上的 0 ,则可选择其中一个 0 ,进行处理,确保每行、每列有且仅有一个 0 打上“ *” ,由此找到 n 个独立 0 的位置 ,得最优解的矩阵,从而求出最优 Assignment Problem .
应用举例:


Step1.从第1行减去75,第2行减去35,第3行减去90,第4行减去45

Step2.从第1列减去0,第2列减去0,第3列减去0,第4列减去5。

现在已经完成了匈牙利算法的第一部
Step3.利用最少的水平线或垂直线覆盖所有的0。

Step4.由于水平线和垂直线的总数是3,少于4,进入Step5。
现在已经完成了匈牙利算法的第二步
Step5.没有被覆盖的最小值是5,没有被覆盖的每行减去最小值5,被覆盖的每列加上最小值5,然后跳转到步骤3.

匈牙利算法已经完成了第三步
Step3.利用最少的水平线或垂直线覆盖所有的0。

Step4.由于水平线和垂直线的总数是3,少于4,进入Step5。
Step5.没有被覆盖的最小值是20,没有被覆盖的每行减去最小值20,被覆盖的每列加上最小值20,然后跳转到步骤3.

Step3.利用最少的水平线或垂直线覆盖所有的0。

Step4.由于水平线和垂直线的总数是4,算法结束,分配结果如下图所示。
在这里插入图片描述
其中,黄色框表示分配结果,左边矩阵的最优分配等价于左边矩阵的最优分配。
L=45+95+55+80;
//本人小白,借鉴了一下大佬的思路,再加上自己的理解。这篇博客是为了捋清楚思路,相当于自己的笔记本,如果强要说是抄袭,本人只能呵呵一笑

猜你喜欢

转载自blog.csdn.net/qq_43646600/article/details/85225030
今日推荐