uvalive 3276 The Great Wall Game

题意:

一个n * n的棋盘上放着n个棋子,现在要求把这n个棋子用最少的步数移到同一条直线上,即同一列同一行或者同一对角线(两条)。输出最少的步数(只能往四个方向移动,即正东,正西,正南,正北)。

思路:

每个棋子唯一对应一个格子,每个棋子不能在同一个格子,那么就相当于一个二分图(强行二分图)。

因为n很小,所以可以枚举每一行,每一列,两条对角线,然后每个点移动到每一条直线的每一个格子都有一个距离,那么这个点就向格子连一条权值为距离的边,这个问题就转化成了求所有最佳完美的匹配中的最小值,用KM算法。

因为我们求的是最小步数,所以求的是带权二分图的最小匹配

求最小匹配,就将每一条边的权值取反,然后求最大匹配,再将最后的结果取反就得到了最小匹配的结果。

复杂度为O(n^4)。

注意:输出很坑,每一个答案后都有一个换行,并不是两个中间输出一个,也就是说,最后一个后面也有换行。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <vector>
  5 using namespace std;
  6 
  7 const int N = 20;
  8 const int inf = 0x3f3f3f3f;
  9 
 10 int love[N][N];
 11 int lx[N],ly[N];
 12 bool visx[N],visy[N];
 13 int match[N];
 14 int slack[N];
 15 
 16 struct node
 17 {
 18     int x,y;
 19     
 20     node(int aa,int bb)
 21     {
 22         x = aa;
 23         y = bb;
 24     }
 25 };
 26 
 27 vector<node> vn;
 28 
 29 int mabs(int x)
 30 {
 31     return x >= 0 ? x : -x;
 32 }
 33 
 34 bool dfs(int u,int n)
 35 {
 36     visx[u] = 1;
 37     
 38     for (int i = 1;i <= n;i++)
 39     {
 40         if (visy[i]) continue;
 41         
 42         int gap = lx[u] + ly[i] - love[u][i];
 43         
 44         if (gap == 0)
 45         {
 46             visy[i] = 1;
 47             
 48             if (match[i] == -1 || dfs(match[i],n))
 49             {
 50                 match[i] = u;
 51                 return true;
 52             }
 53         }
 54         else
 55         {
 56             slack[i] = min(gap,slack[i]);
 57         }
 58     }
 59     
 60     return false;
 61 }
 62 
 63 int km(int n)
 64 {
 65     memset(match,-1,sizeof(match));
 66     memset(ly,0,sizeof(ly));
 67     
 68     for (int i = 1;i <= n;i++)
 69     {
 70         lx[i] = love[i][1];
 71         
 72         for (int j = 2;j <= n;j++)
 73         {
 74             lx[i] = max(lx[i],love[i][j]);
 75         }
 76     }
 77     
 78     for (int i = 1;i <= n;i++)
 79     {
 80         memset(slack,inf,sizeof(slack));
 81         
 82         while (1)
 83         {
 84             memset(visx,0,sizeof(visx));
 85             memset(visy,0,sizeof(visy));
 86             
 87             if (dfs(i,n)) break;
 88             
 89             int d = inf;
 90             
 91             for (int j = 1;j <= n;j++)
 92             {
 93                 if (!visy[j]) d = min(d,slack[j]);
 94             }
 95             
 96             for (int j = 1;j <= n;j++)
 97             {
 98                 if (visx[j]) lx[j] -= d;
 99                 
100                 if (visy[j]) ly[j] += d;
101             }
102         }
103 
104     }
105         
106     
107     int res = 0;
108     
109     for (int i = 1;i <= n;i++)
110     {
111         res += love[match[i]][i];
112     }
113     
114     return res;
115 }
116 
117 int main()
118 {
119     int n;
120     int kase = 0;
121     
122     while (scanf("%d",&n) != EOF && n)
123     {
124         vn.clear();
125         
126         for (int i = 0;i < n;i++)
127         {
128             int a,b;
129             
130             scanf("%d%d",&a,&b);
131             
132             vn.push_back(node(a,b));
133         }
134         
135         //if (kase) printf("
");
136         
137         int ans = 1e8;
138         
139         for (int i = 1;i <= n;i++)
140         {
141             for (int j = 0;j < vn.size();j++)
142             {
143                 for (int k = 1;k <= n;k++)
144                 {
145                     int dx = mabs(vn[j].x - i);
146                     int dy = mabs(vn[j].y - k);
147                     love[j+1][k] = -(dx + dy);
148                 }
149             }
150             
151             int tmp = -km(n);
152             
153             //printf("%d **
",tmp);
154             
155             ans = min(tmp,ans);
156         }
157         
158         for (int i = 1;i <= n;i++)
159         {
160             for (int j = 0;j < vn.size();j++)
161             {
162                 for (int k = 1;k <= n;k++)
163                 {
164                     int dy = mabs(vn[j].y - i);
165                     int dx = mabs(vn[j].x - k);
166                     love[j+1][k] = -(dx + dy);
167                 }
168             }
169             
170             int tmp = -km(n);
171             
172             ans = min(tmp,ans);
173             
174             //printf("%d **
",tmp);
175         }
176         
177         for (int i = 1;i <= n;i++)
178         {
179             for (int j = 0;j < vn.size();j++)
180             {
181                 int dx = mabs(vn[j].x - i);
182                 int dy = mabs(vn[j].y - i);
183                 
184                 love[j+1][i] = -(dx + dy);
185             }
186         }
187         
188         ans = min(ans,-km(n));
189         
190         for (int i = 1;i <= n;i++)
191         {
192             for (int j = 0;j < vn.size();j++)
193             {
194                 int dx = mabs(vn[j].x - i);
195                 int dy = mabs(vn[j].y - (n - i + 1));
196                 
197                 love[j+1][i] = -(dx + dy);
198             }
199         }
200         
201         ans = min(ans,-km(n));
202         
203         printf("Board %d: %d moves required.

",++kase,ans);
204     }
205     
206     return 0;
207 }
原文地址:https://www.cnblogs.com/kickit/p/8809138.html