uva 1411 Ants

题意:

一个平面上有n个黑色的点,n个白色的点,要求黑色的点与白色点之间一一配对,且线段之间不相交。

思路:

线段不相交并不好处理,想了很久想不出,所以看了蓝书的讲解。

一个很明显的结论是,不相交的线段一定比相交的线段短,如图:一个较为直观的例子。

由于点之间一一对应,所以肯定用二分图匹配,然后要使得所有线段之和最短,那么就是求一个带权最小匹配,上KM算法解决。

把所有的边权取负值,求最大匹配即可。

代码:

  1 #include <stdio.h>
  2 #include <math.h>
  3 #include <string.h>
  4 #include <algorithm>
  5 #include <vector>
  6 using namespace std;
  7 
  8 const int N = 105;
  9 
 10 double mp[N][N];
 11 
 12 struct node
 13 {
 14     double x,y;
 15     node(double a,double b)
 16     {
 17         x = a;
 18         y = b;
 19     }
 20 };
 21 
 22 vector<node> nx,ny;
 23 
 24 bool vis_x[N],vis_y[N];
 25 int match[N];
 26 double lx[N],ly[N];
 27 double slack[N];
 28 int ma[N];
 29 
 30 double cal(int i,int j)
 31 {
 32     double dx = pow(nx[i].x - ny[j].x,2);
 33     double dy = pow(nx[i].y - ny[j].y,2);
 34     
 35     return sqrt(dx + dy);
 36 }
 37 
 38 bool dfs(int u,int n)
 39 {
 40     vis_x[u] = 1;
 41     
 42     for (int i = 0;i < n;i++)
 43     {
 44         if (vis_y[i]) continue;
 45         
 46         double gap = lx[u] + ly[i] - mp[u][i];
 47         
 48         //getchar();
 49         
 50         //printf("%.6f %.6f %.6f %.6f\n",lx[u],ly[i],mp[u][i],gap);
 51         
 52         if (fabs(gap) < 1e-6)
 53         {
 54             vis_y[i] = 1;
 55             
 56             if (match[i] == -1 || dfs(match[i],n))
 57             {
 58                 match[i] = u;
 59                 return true;
 60             }
 61         } 
 62         else
 63         {
 64             slack[i] = min(slack[i],gap);
 65         }
 66     }
 67     
 68     return false;
 69 }
 70 
 71 void km(int n)
 72 {
 73     memset(ly,0,sizeof(ly));
 74     memset(match,-1,sizeof(match));
 75     
 76     for (int i = 0;i < n;i++)
 77     {
 78         lx[i] = mp[i][0];
 79         
 80         for (int j = 1;j < n;j++)
 81         {
 82             lx[i] = max(lx[i],mp[i][j]);
 83         }
 84     }
 85     
 86     for (int i = 0;i < n;i++)
 87     {
 88         for (int j = 0;j < n;j++) slack[j] = 1e15;
 89         //printf("gg");
 90         while (1)
 91         {
 92             //printf("233");
 93             memset(vis_x,0,sizeof(vis_x));
 94             memset(vis_y,0,sizeof(vis_y));
 95             
 96             if (dfs(i,n)) break;
 97             
 98             double d = 1e15;
 99             
100             for (int j = 0;j < n;j++)
101             {
102                 if (!vis_y[j]) d = min(slack[j],d);
103             }
104             
105             for (int j = 0;j < n;j++)
106             {
107                 if (vis_x[j]) lx[j] -= d;
108                 
109                 if (vis_y[j]) ly[j] += d;
110             }
111             
112             //getchar();
113             
114             //printf("%.6f **\n",d);
115         }
116     }
117 }
118 
119 int main()
120 {
121     int n;
122     int kase = 0;
123     
124     while (scanf("%d",&n) != EOF)
125     {
126         if (kase++) printf("\n");
127         
128         nx.clear();
129         ny.clear();
130         
131         for (int i = 0;i < n;i++)
132         {
133             double x,y;
134             scanf("%lf%lf",&x,&y);
135             
136             nx.push_back(node(x,y));
137         }
138         
139         for (int i = 0;i < n;i++)
140         {
141             double x,y;
142             scanf("%lf%lf",&x,&y);
143             
144             ny.push_back(node(x,y));
145         }
146         
147         for (int i = 0;i < n;i++)
148         {
149             for (int j = 0;j < n;j++)
150             {
151                 mp[i][j] = -cal(i,j);
152             }
153         }
154         
155         km(n);
156         
157         for (int i = 0;i < n;i++)
158         {
159             int a = i + 1,b = match[i] + 1;
160             ma[b] = a;
161         }
162         
163         for (int i = 0;i < n;i++)
164         {
165             printf("%d\n",ma[i+1]);
166         }
167     }
168     
169     return 0;
170 }

 

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