二分图带权值的最大匹配(最大完美匹配)------KM算法

学习原博客-----》》》》https://www.cnblogs.com/wenruo/p/5264235.html

 入门题:::hdu2255

                                                       奔小康赚大钱

                                  Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                    Total Submission(s): 18527    Accepted Submission(s): 7827

 

Problem Description

传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).

 Input

输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。

output 

 请对每组数据输出最大的收入值,每组的输出占一行。

Sample Input

2

100 10

15 23

Sample Output

 123

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
//说明:此题主动方在房子,被动方是人 


int price[301][301];//price[i][j]表示人i和房子j之间建立的价格值 
int person[301],home[301];//期望值
bool vis_person[301];//人i有没有被访问过 
bool vis_home[301];//房子j有没有被访问过 
int match[301];//match[i]=u;人i已经被安排到房子u中 
int slack[301];//记录每个人能被安排到房子中最小能增加的期望值 
int n;

bool dfs(int u){
	vis_home[u]=true;
	for(int i=1;i<=n;i++){
		if(vis_person[i])continue;//每一轮匹配,每个人只被'尝试'安排一次 
		int gap=home[u]+person[i]-price[i][u];
		if(gap==0){//如果符合要求(期望值之和等于之间价格值) 
			vis_person[i]=true;//访问标记 
			if(match[i]==-1||dfs(match[i])){//之前没有被安排到房子中去,否则检测其匹配的房子能不能安排进别的人去 
				match[i]=u;//安排到房子u中 
				return true;
			}
		}//否则更新该人要想能安排到房子中所能增加的最小的期望值 
		else slack[i]=min(slack[i],gap);
	}
	//如果该房子未找到,返回false 
	return false;
}
int KM(){
	memset(match,-1,sizeof(match));//初始化都未匹配到 
	memset(person,0,sizeof(person));//初始化每个人的期望值都为零 
	//每个房子的期望值为左右人对该房子的出价中的最大值 
	for(int i=1;i<=n;i++){
		home[i]=price[1][i];
		for(int j=2;j<=n;j++){
			home[i]=max(home[i],price[j][i]);
		}
	}
	//为每个房子安排人 
	for(int i=1;i<=n;i++){
		memset(slack,INF,sizeof(slack));//要找最小值,便初始化无穷大 
		//为房子i安排人 
		while(1){
			//每一轮匹配时都未访问过 
			memset(vis_home,false,sizeof(vis_home));
			memset(vis_person,false,sizeof(vis_person));
			if(dfs(i))break;//如果可以匹配到,break,未下一个房子安排人 
			int d=INF;//如果找不到,就降低home的期望值
			//找最小可降低的期望值 
			for(int i=1;i<=n;i++){
				//已经被安排的人不用做参考 
				if(!vis_person[i])d=min(d,slack[i]);
			}
			for(int i=1;i<=n;i++){
				//所有访问过的房子降低期望值 
				if(vis_home[i])home[i]-=d;
				//所有访问过的人增加期望值 
				if(vis_person[i])person[i]+=d;
				//没有访问过的人,因为房子的期望值的降低,应容易被安排到房子 
				else slack[i]-=d;//最小可增加的期望值减小 
			}	
		}		
	}
	//匹配完成,累加匹配成功的价格值 
	int res=0;
	for(int i=1;i<=n;i++){
		res+=price[i][match[i]];
	}
	return res;
}

int main(){
	int x;
	while(scanf("%d",&n)!=EOF){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				scanf("%d",&x);
				price[i][j]=x;		
			}
		}
		cout<<KM()<<endl;
	}
	return 0;
}
//            /\       |  /  |**、
//			 /  \      | /   |   \
//			/    \     |/    |   /  _____                      ____   |  /
//		   /------\    |\    |__/  /     \  \      /\      /  /    \  | /
//		  /        \   | \   |    /       \  \    /  \    /  /______\ |/
//		 /          \  |  \  |    \       /   \  /    \  /   \        |
//      /            \ |   \ |     \_____/     \/      \/     \_____  |
/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */
// warm heart, wagging tail,and a smile just for you!
//
//                            _ooOoo_
//                           o8888888o
//                           88" . "88
//                           (| -_- |)
//                           O\  =  /O
//                        ____/`---'\____
//                      .'  \|     |//  `.
//                     /  \|||  :  |||//  \
//                    /  _||||| -:- |||||-  \
//                    |   | \\  -  /// |   |
//                    | \_|  ''\---/''  |   |
//                    \  .-\__  `-`  ___/-. /
//                  ___`. .'  /--.--\  `. . __
//               ."" '<  `.___\_<|>_/___.'  >'"".
//              | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//              \  \ `-.   \_ __\ /__ _/   .-` /  /
//         ======`-.____`-.___\_____/___.-`____.-'======
//                            `=---='
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
发布了186 篇原创文章 · 获赞 38 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43746332/article/details/103223970