Gym 100273A Ants

来源:互联网 发布:trpg知乎 编辑:程序博客网 时间:2024/05/16 04:04

Gym 100273A Ants

二分图最大完美匹配

题意

给出n个蚁群与n个苹果树坐标(任意三点不共线),使得每一个蚁群对应一个苹果树,且蚁群到苹果树的路线不相交。保证有解,求总距离最短的方案。

思路

二分图最大(小)匹配,将权值变为负的来处理最小匹配,别忘了初始化也要初始化成负无穷。

容易想到完美匹配模型。
然后考虑路线相交的问题。对于四个定点,构成的两条不共点的线段。相交线段长度之和一定大于不相交的长度之和。
对于每条边的权值,另其等于两点的距离。那么问题转化为求最佳匹配(权值最小)。
由于KM算法一般是求权值最大的最佳匹配,因此套用KM算法时,可以让权值变为负值,这样问题转化为求权值最大的最佳匹配。
注意问题要输出的是蚁群所连接的苹果树编号。
那么匹配的时候,应该枚举每个苹果树,为其寻找匹配的蚁群。即L记录的是蚁群对应的苹果树编号。

大概就是熟悉一下板子。
余勇的板子感觉好复杂,不过比我在网上找的快一些。

代码

余勇的板子

#include<bits/stdc++.h>#include<stdlib.h>#define M(a,b) memset(a,b,sizeof(a))#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1using namespace std;const int MAXN=107;const int oo=0x3f3f3f3f;typedef long long LL;double w[MAXN][MAXN], x[MAXN], slack[MAXN], y[MAXN];int prev_x[MAXN], prev_y[MAXN], son_y[MAXN], par[MAXN];int lx, ly, pop;///w表示带权图///pop表示一侧点数///返回最大完美匹配权值///son_y表示匹配方案void adjust(int v){    son_y[v]=prev_y[v];    if(prev_x[son_y[v]]!=-2)        adjust(prev_x[son_y[v]]);}bool fin_d(int v){    for(int i=1;i<=pop;i++)    {        if(prev_y[i]==-1)        {            if(slack[i]>x[v]+y[i]-w[v][i])            {                slack[i]=x[v]+y[i]-w[v][i];                par[i]=v;            }            if(x[v]+y[i]==w[v][i])            {                prev_y[i]=v;                if(son_y[i]==-1)                {                    adjust(i);                    return true;                }                if(prev_x[son_y[i]]!=-1) continue;                prev_x[son_y[i]]=i;                if(fin_d(son_y[i])) return true;            }        }    }    return false;}int km(){    double m=-oo;    for(int i=1;i<=pop;i++)    {        son_y[i]=-1;        y[i]=0;    }    for(int i=1;i<=pop;i++)    {        x[i]=-oo;        for(int j=1;j<=pop;j++)            x[i]=max(x[i], w[i][j]);    }    bool flag;    for(int i=1;i<=pop;i++)    {        for(int j=1;j<=pop;j++)        {            prev_x[j]=prev_y[j]=-1;            slack[j]=oo;        }        prev_x[i]=-2;        if(fin_d(i)) continue;        flag=false;        while(!flag)        {            m=oo;            for(int j=1;j<=pop;j++)            {                if(prev_y[j]==-1)                    m=min(m, slack[j]);            }            for(int j=1;j<=pop;j++)            {                if(prev_x[j]!=-1)                    x[j]-=m;                if(prev_y[j]!=-1)                    y[j]+=m;                else slack[j]-=m;            }            for(int j=1;j<=pop;j++)            {                if(prev_y[j]==-1&&!slack[j])                {                    prev_y[j]=par[j];                    if(son_y[j]==-1)                    {                        adjust(j);                        flag=true;                        break;                    }                    prev_x[son_y[j]]=j;                    if(fin_d(son_y[j]))                    {                        flag=true;                        break;                    }                }            }        }    }    int ans=0;    for(int i=1;i<=pop;i++)        ans+=w[son_y[i]][i];    return ans;}LL px[MAXN], py[MAXN];double getDis(int i, LL d1, LL d2){    return sqrt(((double)px[i]-(double)d1)*((double)px[i]-(double)d1)+        ((double)py[i]-(double)d2)*((double)py[i]-(double)d2));}int main(){    freopen("ants.in", "r", stdin);    freopen("ants.out", "w", stdout);    memset(w, 0, sizeof(w));    int n;scanf("%d", &n);    for(int i=1;i<=n;i++)    {        scanf("%I64d %I64d", &px[i], &py[i]);    }    for(int i=1;i<=n;i++)    {        LL ta, tb;scanf("%I64d %I64d", &ta, &tb);        for(int j=1;j<=n;j++)        {            w[i][j]=-getDis(j, ta, tb);        }    }    pop=n;    km();    for(int i=1;i<=n;i++)        printf("%d\n", son_y[i]);    return 0;}

其他一个板子

#include<bits/stdc++.h>#define M(a,b) memset(a,b,sizeof(a))#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1using namespace std;const int MAXN=107;const double eps=1e-10;const double oo=1e9;typedef long long LL;///W表示带权图///psum表示一侧点数///返回最大完美匹配权值///son_y表示匹配方案double W[MAXN][MAXN], Lx[MAXN], Ly[MAXN], slack[MAXN];int L[MAXN], psum;bool S[MAXN], T[MAXN];bool match(int u){    S[u]=true;    for(int j=1; j<=psum; ++j)        if(!T[j])        {            if((Lx[u]+Ly[j]-W[u][j])<eps)            {                T[j]=true;                if(!L[j]||match(L[j]))                {                    L[j]=u;                    return true;                }            }            else slack[j]=min(slack[j], Lx[u]+Ly[j]-W[u][j]);        }    return false;}LL KM(){    for(int i=1; i<=psum; ++i)    {        L[i]=Ly[i]=0;        Lx[i]=-oo;        for(int j=1; j<=psum; ++j) Lx[i]=max(Lx[i], W[i][j]);    }    for(int i=1; i<=psum; ++i)    {        for(int j=1; j<=psum; ++j) slack[j]=oo;        while(1)        {            for(int j=1; j<=psum; ++j) S[j]=T[j]=0;            if(match(i)) break;            double a=oo;            for(int j=1; j<=psum; ++j) if(!T[j]) a=min(a, slack[j]);            for(int j=1; j<=psum; ++j)            {                if(S[j]) Lx[j]-=a;                if(T[j]) Ly[j]+=a;            }        }    }    LL ans=0;    /*for(int i=1;i<=psum;i++)    {        ans+=W[L[i]][i];    }*/    return ans;}double px[MAXN], py[MAXN];double qx[MAXN], qy[MAXN];int main(){    freopen("ants.in", "r", stdin);    freopen("ants.out", "w", stdout);    int n;    while(scanf("%d", &n)==1)    {        memset(W, 0, sizeof(W));        for(int i=1;i<=n;i++) scanf("%lf %lf", &px[i], &py[i]);        for(int i=1;i<=n;i++) scanf("%lf %lf", &qx[i], &qy[i]);        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)            {                W[i][j]=-sqrt((qx[i]-px[j])*(qx[i]-px[j])+(qy[i]-py[j])*(qy[i]-py[j]));            }        }        psum=n;        KM();        for(int i=1;i<=n;i++)            printf("%d\n", L[i]);    }    return 0;}
原创粉丝点击