uva 11383 Golden Tiger Claw

题意:

给出一个n * n的矩阵,要求给每一行和每一列安排一个数字,使得对于每个数字a[i][j],这一行安排的数字row[i]和这一列安排的数字col[j]满足row[i] + col[j] >= a[i][j]。要求使得每一行安排的数字和每一列安排的数字之和最小。输出每一行和每一列安排的数字,再输出最小值。

思路:

对于row[i] + col[j] >= a[i][j]这个条件,可以联想到KM算法中的一个式子lx[i] + ly[j] >= w[i][j],于是就可以把每一行安排的值视为左顶标,每一列安排的值视为右顶标,然后进行一次KM算法求最大匹配,那么得到的左右顶标之和就是最小的,即每一行安排的数字和每一列安排的数字之和最小。

有两个地方比较难想:

第一是求的是最小值,但是求的却是最大匹配,不是最小匹配,因为我们求的最后结果是满足lx[i] + ly[j] >= w[i][j]的,但是最小匹配满足的条件是lx[i] + ly[j] >= -w[i][j],这不满足条件。

第二是如何证明求出来的是最小值,因为求出的匹配是一个导出子图,而导出子图的每一条边都满足lx[i] + ly[j] == w[i][j],如果把这个结果减小,那么必然存在某些边有lx[i] + ly[j] < w[i][j],这样就不满足题中所给条件。

复杂度O(n^3)。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 const int N = 505;
  7 const int inf = 0x3f3f3f3f;
  8 
  9 int lx[N],ly[N];
 10 bool vis_x[N],vis_y[N];
 11 int slack[N];
 12 int match[N];
 13 int w[N][N];
 14 
 15 bool dfs(int u,int n)
 16 {
 17     vis_x[u] = 1;
 18     
 19     for (int i = 0;i < n;i++)
 20     {
 21         if (vis_y[i]) continue;
 22         
 23         int gap = lx[u] + ly[i] - w[u][i];
 24         
 25         if (gap == 0)
 26         {
 27             vis_y[i] = 1;
 28             
 29             if (match[i] == -1 || dfs(match[i],n))
 30             {
 31                 match[i] = u;
 32                 return true;
 33             }
 34         }
 35         else
 36         {
 37             slack[i] = min(slack[i],gap);
 38         }
 39     }
 40     
 41     return false;
 42 }
 43 
 44 int km(int n)
 45 {
 46     memset(match,-1,sizeof(match));
 47     memset(ly,0,sizeof(ly));
 48     //for (int i = 0;i < n;i++) lx[i] = -inf;
 49     
 50     for (int i = 0;i < n;i++)
 51     {
 52         lx[i] = w[i][0];
 53         
 54         for (int j = 1;j < n;j++)
 55         {
 56             lx[i] = max(lx[i],w[i][j]);
 57         }
 58     }
 59     
 60     for (int i = 0;i < n;i++)
 61     {
 62         memset(slack,inf,sizeof(slack));
 63         
 64         while (1)
 65         {
 66             memset(vis_x,0,sizeof(vis_x));
 67             memset(vis_y,0,sizeof(vis_y));
 68             
 69             if (dfs(i,n)) break;
 70             
 71             int d = inf;
 72             
 73             for (int j = 0;j < n;j++)
 74             {
 75                 d = min(d,slack[j]);
 76             }
 77             
 78             for (int j = 0;j < n;j++)
 79             {
 80                 if (vis_x[j]) lx[j] -= d;
 81                 
 82                 if (vis_y[j]) ly[j] += d;
 83                 //else slack[j] -= d;
 84             }
 85         }
 86     }
 87     
 88     int ans = 0;
 89     
 90     for (int i = 0;i < n;i++)
 91     {
 92         ans += w[match[i]][i];
 93     }
 94     
 95     return ans;
 96 }
 97 
 98 int main()
 99 {
100     int n;
101     
102     while (scanf("%d",&n) != EOF)
103     {
104         for (int i = 0;i < n;i++)
105         {
106             for (int j = 0;j < n;j++)
107             {
108                 int t;
109                 
110                 scanf("%d",&t);
111                 
112                 w[i][j] = t;
113             }
114         }
115         
116         
117         
118         int res = km(n);
119         int ans = 0;
120         
121         for (int i = 0;i < n;i++)
122         {
123             ans += (lx[i]);
124             printf("%d%c",lx[i],i == n - 1 ? '\n' : ' ');
125         }
126         
127         for (int i = 0;i < n;i++)
128         {
129             ans += (ly[i]);
130             printf("%d%c",ly[i],i == n - 1 ? '\n' : ' ');
131         }
132         
133         printf("%d\n",res);
134     }
135     
136     return 0;
137 }

 

posted @ 2018-04-12 17:23  qrfkickit  阅读(120)  评论(0编辑  收藏  举报