zoukankan      html  css  js  c++  java
  • UVALive 4043 Ants 蚂蚁(二分图最佳完美匹配,KM算法)

    题意:

      有n个蚂蚁n棵树,蚂蚁与树要配对,在配对成功的一对之间连一条线段,要求所有线段不能相交。按顺序输出蚂蚁所匹配的树。

    思路:

      这个题目真是技巧啊,不能用贪心来为每个蚂蚁选择最近的树,这样很可能是相交了的。

      整体最优能让每条线段不相交,证明:

      假设a1-b1与a2-b2相交。则dis(a1,b1)+dis(a2,b2)>=dis(a1,b2)+dis(a2,b1)。如果我们所决定的最优匹配是按照整体距离最短来匹配的,那么dis(a1,b1)+dis(a2,b2)必定小于dis(a1,b2)+dis(a2,b1),否则,与最优矛盾。推广到整个图就是匹配图中任意两个点都是最优的,否则我们一定可以用更优的方式来替代他们。而整体最优靠的是KM算法。注意到,本题是完全二分图。

      Tips:要选的是整体权值最小,只需要将边权置为距离相反数再跑KM算法即可。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int N=110;
      4 int antx[N], anty[N], treex[N], treey[N];
      5 double g[N][N];     //距离
      6 
      7 inline double dis(int a,int b)
      8 {
      9     return sqrt((treex[a]-antx[b])*(treex[a]-antx[b])+(treey[a]-anty[b])*(treey[a]-anty[b]));
     10 }
     11 
     12 int n;
     13 double Lx[N], Ly[N], slack[N];
     14 int girl[N];
     15 int S[N], T[N];
     16 
     17 bool DFS(int x)
     18 {
     19     S[x]=true;
     20     for(int i=1; i<=n; i++)
     21     {
     22         if(T[i])    continue;
     23         double tmp=Lx[x]+Ly[i]-g[x][i];
     24         if(tmp<1e-6)
     25         {
     26             T[i]=true;
     27             if(girl[i]==0 || DFS(girl[i]))
     28             {
     29                 girl[i]=x;
     30                 return true;
     31             }
     32         }
     33         else if(slack[i]>tmp)
     34             slack[i]=tmp;
     35     }
     36     return false;
     37 }
     38 
     39 void KM(int n)
     40 {
     41     for(int i=1; i<=n; i++) //初始化工作
     42     {
     43         girl[i]=0;
     44         Lx[i]=-1e19;
     45         Ly[i]=0.0;
     46         for(int j=1; j<=n; j++)
     47             Lx[i]=max(Lx[i], g[i][j]);
     48     }
     49     for(int i=1; i<=n; i++) //对于每个树
     50     {
     51         for(int j=1; j<=n; j++) slack[j]=1e19;
     52         while(1)
     53         {
     54             memset(S, 0, sizeof(S));
     55             memset(T, 0, sizeof(T));
     56             if( DFS(i) )    break;      //找到匹配的蚂蚁
     57 
     58 
     59             double d=1e19;
     60             for(int j=1; j<=n; j++) //找最小D
     61             {
     62                 if(!T[j] && d>slack[j])
     63                     d=slack[j];
     64             }
     65 
     66             for(int j=1; j<=n; j++) //更新树
     67             {
     68                 if(S[j])
     69                     Lx[j]-=d;
     70             }
     71 
     72             for(int j=1; j<=n; j++) //更新蚂蚁
     73             {
     74                 if(T[j])    Ly[j]+=d;
     75                 else        slack[j]-=d;
     76             }
     77         }
     78     }
     79 }
     80 
     81 int main()
     82 {
     83     freopen("input.txt", "r", stdin);
     84     int k=0;
     85     while(~scanf("%d",&n))
     86     {
     87         if(k)   printf("
    ");
     88         k++;
     89         for(int i=1; i<=n; i++)
     90             scanf("%d%d", &antx[i], &anty[i]);      //ant
     91         for(int i=1; i<=n; i++)
     92             scanf("%d%d", &treex[i], &treey[i]);    //apple tree
     93 
     94 
     95         for(int i=1; i<=n; i++)
     96             for(int j=1; j<=n; j++)
     97                 g[i][j]=-dis(i,j);
     98 
     99         KM(n);
    100         for(int i=1; i<=n; i++)
    101             printf("%d
    ", girl[i]);    //ans为girl
    102     }
    103     return 0;
    104 }
    AC代码
  • 相关阅读:
    教程:在 Visual Studio 中开始使用 Flask Web 框架
    教程:Visual Studio 中的 Django Web 框架入门
    vs2017下发现解决python运行出现‘No module named "XXX""的解决办法
    《sqlite权威指南》读书笔记 (一)
    SQL Server手工插入标识列
    hdu 3729 I'm Telling the Truth 二分图匹配
    HDU 3065 AC自动机 裸题
    hdu 3720 Arranging Your Team 枚举
    virtualbox 虚拟3台虚拟机搭建hadoop集群
    sqlserver 数据行统计,秒查语句
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4719582.html
Copyright © 2011-2022 走看看