hdu 2255
2014-11-09 12:53
381 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255
中文题:就不翻译了- -。
由题目可知,要求的就是使左右两个集合的最佳匹配,可以用KM算法解决。
主要是第一次用,不熟练,上个模板。
中文题:就不翻译了- -。
由题目可知,要求的就是使左右两个集合的最佳匹配,可以用KM算法解决。
主要是第一次用,不熟练,上个模板。
/* * ThinkingLion.cpp * * Created on: 2014年1月29日 * Author: dell */ #include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<algorithm> #include<iomanip> #include<vector> #include<time.h> #include<queue> #include<stack> #include<iterator> #include<math.h> #include<stdlib.h> #include<limits.h> //#define ONLINE_JUDGE #define eps 1e-8 #define INF 0x7fffffff #define FOR(i,a) for((i)=0;i<(a);(i)++) #define MEM(a) (memset((a),0,sizeof(a))) #define sfs(a) scanf("%s",a) #define sf(a) scanf("%d",&a) #define sfI(a) scanf("%I64d",&a); #define pf(a) printf("%d\n",a) #define pfs(a) printf("%s\n",a) #define sfd(a,b) scanf("%d%d",&a,&b) #define for1(i,a,b) for(int i=(a);i<b;i++) #define for2(i,a,b) for(int i=(a);i<=b;i++) #define clr1(a) memset(a,0,sizeof(a)) #define clr2(a) memset(a,-1,sizeof(a)) const double PI=acos(-1.0); template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} template<class T> inline T Min(T a,T b){return a<b?a:b;} template<class T> inline T Max(T a,T b){return a>b?a:b;} using namespace std; #define N 320 int n,nx,ny; int link ,lx ,ly ,slack ; int visx ,visy ,w ; int DFS(int x){ visx[x]=1; for(int y=1;y<=ny;y++){ if(visy[y]) //略过已经被访问过的点 continue; int t=lx[x]+ly[y]-w[x][y]; //计算顶点和与权值的差值 if(t == 0){ //若t==0,那么该边是相等子图中的一条边 visy[y]=1; if(link[y] == -1 || DFS(link[y])){ //寻找增广路 link[y]=x; return 1; } }else if(slack[y]>t) //否则的话就更新slack[y]值 slack[y]=t; } return 0; } int KM(){ memset(link,-1,sizeof link); //link[x]=y代表x集合中与y集合中的(x,y)之间匹配 memset(ly,0,sizeof ly); //可行顶标函数在Y集合上的初始值都为0 for(int i=1;i<=nx;i++){ //可行顶标函数在X集合上的初始值为该点到Y集合中匹配边权值最大的那一个 lx[i]=-INF; for(int j=1;j<=ny;j++){ if(w[i][j] > lx[i]) lx[i]=w[i][j]; } } for(int x=1;x<=nx;x++){ //slack(y)= min{ (x,y)| Lx(x)+ Ly(y)- W(x,y),x∈ S, y∉ T } for(int i=1;i<=ny;i++) slack[i]=INF; while(1){ memset(visx,0,sizeof visx); //标记X集合中哪些点被访问过 memset(visy,0,sizeof visy); //标记Y集合中哪些点被访问过 if(DFS(x)) break; //这个点已经在相等子图中了,跳出循环 int d = INF; for(int i=1;i<=ny;i++) //寻找不在集合T中,而且slack[i]最小的值,当做“松弛”值 if(!visy[i] && d>slack[i]) d=slack[i]; for(int i=1;i<=nx;i++) //将集合S中的x点的顶标-d if(visx[i]) lx[i] -= d; for(int i=1;i<=ny;i++) //将集合T中的y点的顶标+d if(visy[i]) ly[i] += d; else slack[i] -= d; //!!将不在T中的y点的顶标-d (因为它所对应的x∈S中的点的顶标lx[i]都减小了d!!) } } int res=0; for(int i=1;i<=ny;i++) //统计匹配的结果,即求最大权匹配 if(link[i] > -1) res+=w[link[i]][i]; return res; } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif while(sf(n)!=EOF){ nx = ny =n; //nx,ny分别是二分图中x,y集合中的点数 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) //输入两个集合之间的权值w sf(w[i][j]); int ans = KM(); printf("%d\n",ans); } return 0; }
相关文章推荐
- hdu 2255 奔小康赚大钱(二分图的最优匹配)
- KM算法模板(HDU_2255)
- hdu 2255 奔小康赚大钱 (km算法模板)
- [ACM] HDU 2255 奔小康赚大钱 (二分图最大权匹配,KM算法)
- HDU 2255 奔小康赚大钱 KM模板题
- HDU 2255 (2/600)
- HDU 2255 奔小康赚大钱
- hdu 2255 奔小康赚大钱(KM算法)
- HDU 2255 奔小康赚大钱 (km入门)
- hdu 2255+hdu 3395
- HDU 2255 奔小康赚大钱 km算法
- hdu 2255 KM算法板子
- HDU-2255-KM算法
- HDU 2255 奔小康赚大钱 POJ 2195 Going Home 最大权完美匹配 KM算法
- HDU - 2255(二分图最大权匹配)
- KM算法 最优匹配(最大权匹配) hdu 2255 奔小康赚大钱 最小权匹配 poj 2195 Going Home
- HDU-#2255 奔小康赚大钱(二分图最佳完美匹配+KM)
- HDU 2255(KM算法)
- 二分图多重匹配(HDU 2255)
- hdu(2255)奔小康赚大钱