UVA 11383 - Golden Tiger Claw【二分图km原理】
来源:互联网 发布:js城市选择器插件 编辑:程序博客网 时间:2024/06/05 06:15
题意:给定nxn的矩阵值,为每行每列找一个row(i) col(i)使得w(i,j)<=row(i)+col(j) 且要求row(i) 从来col(j)总和最小
做法:最开始死活是想不到这货是二分图有毛线关系啊QAQ, 而且,我还以为row col都是已知的数当中找出来的==
引用:
KM算法是通过给每个顶点一个标号(叫做顶标)来把求最大权匹配的问题转化为求完备匹配的问题的。设顶点Xi的顶标为A[i],顶点Yi的顶标为B [i],顶点Xi与Yj之间的边权为w[i,j]。在算法执行过程中的任一时刻,对于任一条边(i,j),A[i]+B[j]>=w[i,j]始终 成立。KM算法的正确性基于以下定理:
若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。
这个定理是显然的。因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和;如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和。所以相等子图的完备匹配一定是二分图的最大权匹配。
初始时为了使A[i]+B[j]>=w[i,j]恒成立,令A[i]为所有与顶点Xi关联的边的最大权,B[j]=0。如果当前的相等子图没有完备匹配,就按下面的方法修改顶标以使扩大相等子图,直到相等子图具有完备匹配为止。
我们求当前相等子图的完备匹配失败了,是因为对于某个X顶点,我们找不到一条从它出发的交错路。这时我们获得了一棵交错树,它的叶子结点全部是X顶点。现在我们把交错树中X顶点的顶标全都减小某个值d,Y顶点的顶标全都增加同一个值d,那么我们会发现:
两端都在交错树中的边(i,j),A[i]+B[j]的值没有变化。也就是说,它原来属于相等子图,现在仍属于相等子图。
两端都不在交错树中的边(i,j),A[i]和B[j]都没有变化。也就是说,它原来属于(或不属于)相等子图,现在仍属于(或不属于)相等子图。
X端不在交错树中,Y端在交错树中的边(i,j),它的A[i]+B[j]的值有所增大。它原来不属于相等子图,现在仍不属于相等子图。
X端在交错树中,Y端不在交错树中的边(i,j),它的A[i]+B[j]的值有所减小。也就说,它原来不属于相等子图,现在可能进入了相等子图,因而使相等子图得到了扩大。
现在的问题就是求d值了。为了使A[i]+B[j]>=w[i,j]始终成立,且至少有一条边进入相等子图,d应该等于min{A[i]+B[j]-w[i,j]|Xi在交错树中,Yi不在交错树中}。
以上就是KM算法的基本思路。但是朴素的实现方法,时间复杂度为O(n4)——需要找O(n)次增广路,每次增广最多需要修改O(n)次顶 标,每次修改顶标时由于要枚举边来求d值,复杂度为O(n2)。实际上KM算法的复杂度是可以做到O(n3)的。我们给每个Y顶点一个“松弛量”函数 slack,每次开始找增广路时初始化为无穷大。在寻找增广路的过程中,检查边(i,j)时,如果它不在相等子图中,则让slack[j]变成原值与A [i]+B[j]-w[i,j]的较小值。这样,在修改顶标时,取所有不在交错树中的Y顶点的slack值中的最小值作为d值即可。但还要注意一点:修改 顶标后,要把所有的slack值都减去d。
说了一堆废话,总而言之就是要求对上了== 所以把数字带进去得出的就是最终结果
#include <stdio.h>#include <string.h>#define M 555#define inf 0x3f3f3f3fusing namespace std;int abs(int x){ return x>0?x:-x;}int n,m,nx,ny;int link[M],lx[M],ly[M],slack[M];///lx,ly为顶标,nx,ny分别为x点集y点集的个数int visx[M],visy[M],w[M][M];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) { visy[y] = 1; if (link[y] == -1||DFS(link[y])) { link[y] = x; return 1; } } else if (slack[y] > t) ///不在相等子图中slack 取最小的 slack[y] = t; } return 0;}int KM(){ int i,j; memset (link,-1,sizeof(link)); memset (ly,0,sizeof(ly)); for (i = 1; i <= nx; i ++) ///lx初始化为与它关联边中最大的 for (j = 1,lx[i] = -inf; j <= ny; j ++) if (w[i][j] > lx[i]) lx[i] = w[i][j]; for (int x = 1; x <= nx; x ++) { for (i = 1; i <= ny; i ++) slack[i] = inf; while (1) { memset (visx,0,sizeof(visx)); memset (visy,0,sizeof(visy)); if (DFS(x)) ///若成功(找到了增广轨),则该点增广完成,进入下一个点的增广 break; ///若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。 ///方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d, ///所有在增广轨中的Y方点的标号全部加上一个常数d int d = inf; for (i = 1; i <= ny; i ++) if (!visy[i]&&d > slack[i]) d = slack[i]; for (i = 1; i <= nx; i ++) if (visx[i]) lx[i] -= d; for (i = 1; i <= ny; i ++) ///修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d if (visy[i]) ly[i] += d; else slack[i] -= d; } } for(int i=1;i<nx;i++) printf("%d ",lx[i]);printf("%d\n",lx[nx]); for(int i=1;i<ny;i++) printf("%d ",ly[i]);printf("%d\n",ly[ny]); int res = 0; for (i = 1; i <= ny; i ++) if (link[i] > -1) res += w[link[i]][i]; return res;}int main(){ //freopen("cin.txt","r",stdin); int n; while(~scanf("%d",&n)) { nx=ny=n; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) scanf("%d",&w[i][j]); // printf("%d ",w[i][j]); } printf("%d\n",KM()); } return 0;}
- UVA 11383 - Golden Tiger Claw【二分图km原理】
- Uva 11383 Golden Tiger Claw(KM算法原理应用)
- UVa:11383 Golden Tiger Claw(KM算法)
- 【UVA】11383 Golden Tiger Claw KM匹配
- uva 11383 Golden Tiger Claw 二分图完美匹配
- UVA 11383 Golden Tiger Claw(最佳二分图匹配)
- UVA 11383 Golden Tiger Claw(KM算法)
- uva 11383 Golden Tiger Claw (KM算法)
- UVA 11383 Golden Tiger Claw
- uva 11383 Golden Tiger Claw km模版题 但为什么Wa了呀? (KM)
- Uva - 11383 - Golden Tiger Claw(二分图最佳完美匹配)
- UVA 11383 - Golden Tiger Claw(二分图完美匹配扩展)
- UVa11383 Golden Tiger Claw ( KM )
- UVA11383 Golden Tiger Claw km算法
- uva 11383 - Golden Tiger Claw(完美匹配)
- UVA11383[Golden Tiger Claw] KM算法的应用
- UVALive 11383 - Golden Tiger Claw(最小权匹配)
- uva 11396 Claw Decomposition 二分图判定
- 关于Java 信号量 Semaphore
- 小何讲进程: Linux进程控制编程 (fork、vfork)
- C#判断参数是否在枚举Enum中
- 垂直居中的方法
- 不平衡学习算法的评估指标
- UVA 11383 - Golden Tiger Claw【二分图km原理】
- 学习项目: mvp+Rxjava+Retrofit
- js获取url中的参数
- iOS面试题学习
- 欢迎使用CSDN-markdown编辑器
- js == 与 === 的区别
- 深入理解Linux内核day05--定时测量
- 使用C++获取文件夹中所有文件名
- Android 清除缓存