UVALive 4043 Ants 蚂蚁(二分图最佳完美匹配,KM算法)
2015-08-10 22:57
316 查看
题意:
有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算法即可。
AC代码
有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算法即可。
#include <bits/stdc++.h> using namespace std; const int N=110; int antx , anty , treex , treey ; double g ; //距离 inline double dis(int a,int b) { return sqrt((treex[a]-antx[b])*(treex[a]-antx[b])+(treey[a]-anty[b])*(treey[a]-anty[b])); } int n; double Lx , Ly , slack ; int girl ; int S , T ; bool DFS(int x) { S[x]=true; for(int i=1; i<=n; i++) { if(T[i]) continue; double tmp=Lx[x]+Ly[i]-g[x][i]; if(tmp<1e-6) { T[i]=true; if(girl[i]==0 || DFS(girl[i])) { girl[i]=x; return true; } } else if(slack[i]>tmp) slack[i]=tmp; } return false; } void KM(int n) { for(int i=1; i<=n; i++) //初始化工作 { girl[i]=0; Lx[i]=-1e19; Ly[i]=0.0; for(int j=1; j<=n; j++) Lx[i]=max(Lx[i], g[i][j]); } for(int i=1; i<=n; i++) //对于每个树 { for(int j=1; j<=n; j++) slack[j]=1e19; while(1) { memset(S, 0, sizeof(S)); memset(T, 0, sizeof(T)); if( DFS(i) ) break; //找到匹配的蚂蚁 double d=1e19; for(int j=1; j<=n; j++) //找最小D { if(!T[j] && d>slack[j]) d=slack[j]; } for(int j=1; j<=n; j++) //更新树 { if(S[j]) Lx[j]-=d; } for(int j=1; j<=n; j++) //更新蚂蚁 { if(T[j]) Ly[j]+=d; else slack[j]-=d; } } } } int main() { freopen("input.txt", "r", stdin); int k=0; while(~scanf("%d",&n)) { if(k) printf("\n"); k++; for(int i=1; i<=n; i++) scanf("%d%d", &antx[i], &anty[i]); //ant for(int i=1; i<=n; i++) scanf("%d%d", &treex[i], &treey[i]); //apple tree for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) g[i][j]=-dis(i,j); KM(n); for(int i=1; i<=n; i++) printf("%d\n", girl[i]); //ans为girl } return 0; }
AC代码
相关文章推荐
- QGraphicsDropShadowEffect
- 360oj 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离。
- Java心得10
- 设置导航条和状态栏透明度效果
- 15-10-常用对象API(String类-练习2-子串的次数)
- 分享一下Mysql常见的几个错误问题及解决方法
- 八大排序算法(三)简单选择排序
- 15-09-常用对象API(String类-练习1-字符串数组排序)
- arpg网页游戏特效播放(一)
- ThinkPHP加载自定义的外部文件和配置文件
- c# 建立局域网远程共享连接,读取共享文件
- 浅谈Git与SVN的使用感受
- Longest Substring Without Repeating Characters
- Linux网络驱动架构
- Velocity + Spring定时器 生成静态页面
- 《C++编程思想》 第十三章 继承和组合 (原书代码+习题+解答)
- word2vec实践(一):预备知识
- 15-08-常用对象API(String类-intern方法)
- 朴素贝叶斯
- ios设置UILabel中文字的不同颜色和字体字号