【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 }
View Code

 

posted @ 2018-07-13 18:03  蒟蒻LQL  阅读(291)  评论(0编辑  收藏  举报