【LA4043 训练指南】蚂蚁 【二分图最佳完美匹配,费用流】
题意
给出n个白点和n个黑点的坐标,要求用n条不相交的线段把他们连接起来,其中每条线段恰好连接一个白点和一个黑点,每个点恰好连接一条线段。
分析
结点分黑白,很容易想到二分图。其中每个白点对应一个X结点,每个黑点对应一个Y点,每个黑点和每个白点相连,权值等于二者的欧几里得距离,建模之后,最佳完美匹配就是问题的解。
为什么用费用流而不用KM呢,因为我不会···
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 9 using namespace std; 10 const int maxN=300; 11 const int maxm=30000+10; 12 const int INF=2147480000; 13 int n; 14 int ax[maxN],bx[maxN],ay[maxN],by[maxN]; 15 16 struct MCMF{ 17 int head[maxN],to[maxm],Next[maxm],from[maxm],flow[maxm],cap[maxm]; 18 double cost[maxm]; 19 int n,m,s,t,sz; 20 int inq[maxN]; 21 double d[maxN]; 22 int p[maxN]; 23 int a[maxN]; 24 25 void init(int n){ 26 this->n=n; 27 sz=-1; 28 memset(head,-1,sizeof(head)); 29 } 30 void AddEdge(int a,int b,int ca,double co){ 31 ++sz; 32 to[sz]=b,from[sz]=a,Next[sz]=head[a],head[a]=sz; 33 flow[sz]=0,cap[sz]=ca,cost[sz]=co; 34 ++sz; 35 to[sz]=a,from[sz]=b,Next[sz]=head[b],head[b]=sz; 36 flow[sz]=ca,cap[sz]=ca,cost[sz]=-co; 37 } 38 bool BellmanFord(int s,int t,int &Flow,double &Cost){ 39 for(int i=0;i<=n;i++)d[i]=INF; 40 memset(inq,0,sizeof(inq)); 41 d[s]=0;inq[s]=1;p[s]=-1;a[s]=INF; 42 queue<int>Q; 43 Q.push(s); 44 while(!Q.empty()){ 45 int u=Q.front();Q.pop(); 46 inq[u]=0; 47 for(int i=head[u];i!=-1;i=Next[i]){ 48 int v=to[i]; 49 if(cap[i]>flow[i]&&d[v]>d[u]+cost[i]){ 50 d[v]=d[u]+cost[i]; 51 p[v]=i; 52 a[v]=min(a[u],cap[i]-flow[i]); 53 if(!inq[v]){ 54 Q.push(v); 55 inq[v]=1; 56 } 57 } 58 } 59 } 60 if(d[t]==INF)return false; 61 Flow+=a[t]; 62 Cost+=d[t]*(double)a[t]; 63 int u=t; 64 65 while(u!=s){ 66 flow[p[u]]+=a[t]; 67 flow[p[u]^1]-=a[t]; 68 u=from[p[u]]; 69 } 70 return true; 71 } 72 73 double Mincost(int s,int t){ 74 int Flow=0; 75 double Cost=0; 76 while(BellmanFord(s,t,Flow,Cost)); 77 return Cost; 78 } 79 }mcmf; 80 81 double dist(int X,int Y){ 82 return sqrt((double)(ax[X]-bx[Y])*(ax[X]-bx[Y])+(double)(ay[X]-by[Y])*(ay[X]-by[Y])); 83 } 84 int main(){ 85 while(scanf("%d",&n)!=EOF){ 86 for(int i=1;i<=n;i++) 87 scanf("%d%d",&ax[i],&ay[i]); 88 for(int i=1;i<=n;i++) 89 scanf("%d%d",&bx[i],&by[i]); 90 mcmf.init(2*n+2); 91 for(int i=1;i<=n;i++) 92 mcmf.AddEdge(0,i,1,0); 93 for(int i=1;i<=n;i++) 94 mcmf.AddEdge(i+n,2*n+1,1,0); 95 for(int i=1;i<=n;i++){ 96 for(int j=1;j<=n;j++){ 97 mcmf.AddEdge(i,j+n,1,dist(i,j)); 98 } 99 } 100 mcmf.Mincost(0,2*n+1); 101 for(int i=1;i<=n;i++){ 102 for(int j=mcmf.head[i];j!=-1;j=mcmf.Next[j]){ 103 if(j%2)continue; 104 int v=mcmf.to[j]; 105 if(mcmf.cap[j]==mcmf.flow[j]){ 106 printf("%d\n",v-n); 107 break; 108 } 109 } 110 } 111 } 112 return 0; 113 }