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代码
  • 相关阅读:
    怎样设定目标(六)如何时刻保持在目标的正确轨道上
    怎样设定目标(五)——设定目标失败的七大原因
    怎样设定目标(四)如何规划成功的新年目标
    怎样设定目标(三)——目标设定前的准备
    CMake笔记(一)
    开源IDE code blocks黑色主题
    函数指针
    getRealPath函数编译报错问题
    Intellij IDEA添加项目依赖
    structs2.8创建拦截器
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4719582.html
Copyright © 2011-2022 走看看