POJ3565 Ants

来源:互联网 发布:宁波网络推广公司 编辑:程序博客网 时间:2024/06/05 00:34

题目大意

有n只蚂蚁,要爬到n棵树上,使每只蚂蚁爬到没棵树上,且两只蚂蚁的路径不能交叉。问是否存在一种方案,若有,输出任意一种方案。

Solution

我们可以发现,若两只蚂蚁的路径交叉,那么交换一下这两只蚂蚁要爬上去的树,肯定能使总路程减少,这样的路径一定不是最小匹配。所以最小匹配一定是合法的路径。所以以任意蚂蚁到任意树间的距离为边权,求出带权二分图最小匹配就一定是其中一种方案。剩下的就是KM的模板。

代码

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>using namespace std;typedef long double ld;const ld INF=1e9;const ld eps=1e-8;int X1[105],Y1[105],X2[105],Y2[105],ma[105],ans[105],n,visx[105],visy[105];ld D[105],C[105],map[105][105],cost[105];int dfs(int u){    visx[u]=1;    for (int v=1;v<=n;v++)    {        if (!visy[v])        {            ld t=C[v]+D[u]-map[u][v];            if (abs(t)<=eps)            {                visy[v]=1;                if (ma[v]==-1||dfs(ma[v]))                {                    ma[v]=u;                    return 1;                }            }            else                 cost[v]=min(cost[v],t);        }    }    return 0;}int sqr(int x){    return x*x;}double calc(int x,int y){    return sqrt((double)(sqr(X1[x]-X2[y])+sqr(Y1[x]-Y2[y])));}void KM(){    memset(ma,-1,sizeof(ma));    memset(C,0,sizeof(C));    for (int i=1;i<=n;i++)    {        D[i]=map[i][1];        for (int j=2;j<=n;j++)            D[i]=max(D[i],map[i][j]);    }    for (int i=1;i<=n;i++)    {        for (int j=1;j<=n;j++)            cost[j]=INF;        while (1)        {            memset(visx,0,sizeof(visx));            memset(visy,0,sizeof(visy));            if (dfs(i)) break;            ld d=INF;            for (int j=1;j<=n;j++)                if (!visy[j]) d=min(d,cost[j]);            for (int j=1;j<=n;j++)            {                if (visx[j]) D[j]-=d;                if (visy[j]) C[j]+=d;                else cost[j]-=d;            }        }    }}int main(){    scanf("%d",&n);    for (int i=1;i<=n;i++)        scanf("%d%d",&X1[i],&Y1[i]);    for (int i=1;i<=n;i++)        scanf("%d%d",&X2[i],&Y2[i]);    for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)            map[i][j]=-calc(i,j);    KM();    for (int i=1;i<=n;i++)        ans[ma[i]]=i;    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]);    return 0;}
原创粉丝点击