UVa 11383 少林决胜(二分图最佳完美匹配)

https://vjudge.net/problem/UVA-11383

题意:

给定一个N×N矩阵,每个格子里都有一个正整数W(i,j)。你的任务是给每行确定一个整数row(i),每列也确定一个整数col(i),使得对于任意格子(i,j),w(i,j)<=row(i)+col(j)。所有的row(i)和col(i)只和应尽量小。

思路:

利用二分图最佳完美匹配当中的l(x)+l(y)>=w(i,j),直接用KM算法即可。

  1 #include<iostream>
  2 #include<string>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<cstdio>
  7 using namespace std;
  8 const int maxn=500+5;
  9
 10 int W[maxn][maxn], n;
 11 int Lx[maxn];
 12 int Ly[maxn];
 13 int Left[maxn];
 14 bool S[maxn], T[maxn];
 15
 16 bool Match(int i)
 17 {
 18     S[i] = true;
 19     for (int j = 1; j <= n; j++)
 20     {
 21         if (Lx[i] + Ly[j] == W[i][j] && !T[j])
 22         {
 23             T[j] = true;
 24             if (!Left[j] || Match(Left[j]))
 25             {
 26                 Left[j] = i;
 27                 return true;
 28             }
 29         }
 30     }
 31     return false;
 32 }
 33
 34 void Update()
 35 {
 36     int a = 1 << 30;
 37     for (int i = 1; i <= n; i++)
 38     {
 39         if (S[i])
 40         {
 41             for (int j = 1; j <= n; j++)
 42             {
 43                 if (!T[j])
 44                 {
 45                     a = min(a, Lx[i] + Ly[j] - W[i][j]);
 46                 }
 47             }
 48         }
 49     }
 50     for (int i = 1; i <= n; i++)
 51     {
 52         if (S[i])
 53             Lx[i] -= a;
 54         if (T[i])
 55             Ly[i] += a;
 56     }
 57 }
 58
 59 void KM()
 60 {
 61     for (int i = 1; i <= n; i++)
 62     {
 63         Left[i] = 0;
 64         Lx[i] = 0;
 65         Ly[i] = 0;
 66         for (int j = 1; j <= n; j++)
 67         {
 68             Lx[i] = max(Lx[i], W[i][j]);
 69         }
 70     }
 71     for (int i = 1; i <= n; i++)
 72     {
 73         while (true)
 74         {
 75             memset(S, 0, sizeof(S));
 76             memset(T, 0, sizeof(T));
 77             if (Match(i))
 78                 break;
 79             else
 80                 Update();
 81         }
 82     }
 83 }
 84
 85 int main()
 86 {
 87     //freopen("D:\\input.txt","r",stdin);
 88     while(~scanf("%d",&n))
 89     {
 90         for(int i=1;i<=n;i++)
 91         {
 92             for(int j=1;j<=n;j++)
 93                 scanf("%d",&W[i][j]);
 94         }
 95         int ans=0;
 96         KM();
 97         for(int i=1;i<=n;i++)
 98         {
 99             printf("%d%c", Lx[i], i == n ? ‘\n‘ : ‘ ‘);
100             ans+=Lx[i];
101         }
102         for(int i=1;i<=n;i++)
103         {
104              printf("%d%c", Ly[i], i == n ? ‘\n‘ : ‘ ‘);
105             ans+=Ly[i];
106         }
107         printf("%d\n",ans);
108     }
109     return 0;
110 }
时间: 2024-09-30 07:20:22

UVa 11383 少林决胜(二分图最佳完美匹配)的相关文章

UVA - 1045 The Great Wall Game(二分图最佳完美匹配)

题目大意:给出棋盘上的N个点的位置.如今问将这些点排成一行或者一列.或者对角线的最小移动步数(每一个点都仅仅能上下左右移动.一次移动一个) 解题思路:暴力+二分图最佳完美匹配 #include <cstdio> #include <cstring> #define N 20 #define INF 0x3f3f3f3f #define abs(x) ((x) > 0 ? (x) : (-(x))) #define max(a,b)((a)>(b)? (a):(b)) #

HDU_2255 二分图最佳完美匹配 KM匈牙利算法

一开始还没看懂这个算法,后来看了陶叔去年的PPT的实例演示才弄懂 用一个lx[]和ly[]来记录X和Y集合中点的权值,有个定理是 lx[i]+ly[j]==w[i][j](边权值) 则该点是最佳匹配,因为首先 那个不等式肯定要>=的,否则就不满足题意了,如果是>则可以去匹配更有价值的边或者把权值降下来让匹配边的潜力更大. 所以只有把握了这个条件,其他就是走一遍最大匹配数.以及up()函数用来在无法匹配的时候,进行其他点的权值降低(也可以说是增广路的搜索)来得到匹配. #include <

UVALive 4043 Ants 蚂蚁(二分图最佳完美匹配)

题意:n个蚂蚁n棵树,蚂蚁与树要配对,在配对成功的一对之间连一条线段,要求所有线段不能相交.按顺序输出蚂蚁所匹配的树. 思路:这个题目真是技巧啊,如果知道要求的就是整体最优,那么就容易做了.而不能用贪心来为每个蚂蚁选择最近的树,这样可能八成还是相交了. 整体最优能让每条线段不相交,证明: 假设a1-b1与a2-b2相交.则dis(a1,b1)+dis(a2,b2)>=dis(a1,b2)+dis(a2,b1).如果我们所决定的最优匹配是按照整体距离最短来匹配的,那么dis(a1,b1)+dis(

HDU 3722 Card Game(二分图最佳完美匹配+KM算法)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3722 1 /* 2 问题 3 将任意的两个字符串进行匹配,使得匹配后权值和最大 4 5 解题思路 6 将任意的字符串的权值计算出来,使用KM算法即可. 7 */ 8 #include<cstdio> 9 #include<cstring> 10 #include<algorithm> 11 using namespace std; 12 13 const int maxn

UVALive 4043 转化最佳完美匹配

首先黑点和白点是组成一个二分图这毫无疑问 关键是题目中要求的所有黑白配的线不能交叉...一开始我也没想到这个怎么转化为二分图里面的算法. 后来看书才知道,如果两两交叉,则可以把两根线当四边形的对角线,连四边形的两条边,则肯定不交叉,而且一个很明显的特征是,不交叉的两条线的他们的长度和 一定比交叉线的长度和小. 于是我们只要求出最小长度的线,就必定是不相交的.那就要用到最佳完美匹配了,首先算出两两点的欧几里得距离,然后取负数,这样走一遍匹配,得到的必定是最短的欧几里得距离,即不相交的线 #incl

codevs 1222 信与信封问题(二分图的完美匹配)

1222 信与信封问题 题目描述 Description John先生晚上写了n封信,并相应地写了n个信封将信装好,准备寄出.但是,第二天John的儿子Small John将这n封信都拿出了信封.不幸的是,Small John无法将拿出的信正确地装回信封中了. 将Small John所提供的n封信依次编号为1,2,…,n:且n个信封也依次编号为1,2,…,n.假定Small John能提供一组信息:第i封信肯定不是装在信封j中.请编程帮助Small John,尽可能多地将信正确地装回信封. 输入

UVaLive 4043 Ants (最佳完美匹配)

题意:给定 n 个只蚂蚁和 n 棵树的坐标,问怎么匹配使得每个蚂蚁到树的连线不相交. 析:可以把蚂蚁和树分别看成是两类,那么就是一个完全匹配就好,但是要他们的连线不相交,那么就得考虑,最佳完美匹配是可以的,为什么呢,假设有两条线段a1-b1和a2-b2,那么如果相交,dist(a1, b1) + dist(a2, b2) > dist(a1, b2) + dist(a2, b1),自己画图看看就好,然后如果是最小的距离,那么就是可以的了,只要在用使得KM匹配时,把权值取反就好. 代码如下: #p

KM算法(二分图的最佳完美匹配)

网上一堆人写KM算法,还没搜出哪个讲得比较好的. KM算法大概过程: (1)初始化Lx数组为该boy的一条权值最大的出边.初始化Ly数组为 0. (2)对于每个boy,用DFS为其找到一个girl对象,顺路记录下S和T集,并更新每个girl的slack值.若不能为其找到对象,则转3. (3)找出非T集合的girl的最小slack值为d,更新S集中的boy和T集中的girl,并且顺路更新非T集中的slack值.对于那个失败的boy继续第2步. 简括之,就是在保持当前权和最高的情况下,尽量为每个bo

UVa 1349 Optimal Bus Route Design (最佳完美匹配)

题意:给定一个有向图,让你找出若干个图,使得每个点恰好属于一个圈,并且总的权和最小. 析:每个点都有唯一的一个圈,也就是说每一点都有唯一的后继,那么我们就可以转换成求一个图的最小权的最佳完全匹配,可以用最小费用流来求, 先把每个结点拆成两个点,假设是x,y,然后建立一个源点,向每个点的x连一条容量为1的边,建立一个汇点,每个点的y向汇点连一条容量为1的边, 每条边u,v,也连接一条容量为1,费用为权值的边,最小求一个最小费用流即可. 代码如下: #pragma comment(linker, "