Ants POJ - 3565
题意:
题目链接
有\(N\)个蚂蚁,\(N\)个苹果,要在每个蚂蚁和一个相应的苹果之间连边,问如何给蚂蚁分配苹果,可以使这些边不相交。\(N<=100\)
思路:
关注两条路径相交的情况
不相交和相交有没有什么区别?
相交的总路径长小于不相交的总路径长
(说起来倒还挺简单的~~)
因此就可做了
具体实现:
我采用的是KM算法,大佬们可以直接上网络流/xyx
注意事项:
除了板子不要敲错,没什么好注意的。。。
code:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=105;
int n,match[N],fm[N];
int nx[N],ny[N],px[N],py[N];
bool vis1[N],vis2[N];
double w[N][N],slack[N],ep1[N],ep2[N];
inline double dis(int ax,int ay,int bx,int by)
{
int d=(ax-bx)*(ax-bx)+(ay-by)*(ay-by);
return sqrt((double)d);
}
bool dfs(int x)
{
vis1[x]=1;
for(int i=1;i<=n;++i)
{
if(vis2[i]) continue;
double gap=ep1[x]+ep2[i]-w[x][i];
if(fabs(gap)<1e-5)
{
vis2[i]=1;
if(match[i]==-1||dfs(match[i]))
{
match[i]=x;
return true;
}
}
else slack[i]=min(slack[i],gap);
}
return false;
}
inline void km()
{
fill(match+1,match+n+1,-1);
fill(ep2+1,ep2+n+1,0);
for(int i=1;i<=n;++i)
{
ep1[i]=w[i][1];
for(int j=2;j<=n;++j)
ep1[i]=max(ep1[i],w[i][j]);
}
for(int i=1;i<=n;++i)
{
fill(slack+1,slack+n+1,1e9);
while(1)
{
fill(vis1+1,vis1+n+1,0);
fill(vis2+1,vis2+n+1,0);
if(dfs(i)) break;
double d=1e9;
for(int j=1;j<=n;++j)
if(!vis2[j]) d=min(d,slack[j]);
for(int j=1;j<=n;++j)
{
if(vis1[j]) ep1[j]-=d;
if(vis2[j]) ep2[j]+=d;
else slack[j]-=d;
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d%d",&nx[i],&ny[i]);
for(int i=1;i<=n;++i)
scanf("%d%d",&px[i],&py[i]);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
w[i][j]=-dis(nx[i],ny[i],px[j],py[j]);
km();
for(int i=1;i<=n;++i)fm[match[i]]=i;
for(int i=1;i<=n;++i)
printf("%d\n",fm[i]);
return 0;
}
NO PAIN NO GAIN