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;
}
posted @ 2020-03-21 14:21  BILL666  阅读(149)  评论(0编辑  收藏  举报