nefu485分配问题(二分图的最佳匹配)

来源:互联网 发布:java交换两个变量的值 编辑:程序博客网 时间:2024/05/29 01:55

分配问题

Time Limit 1000ms

Memory Limit 65536K

description

    有n件工作要分配给n个人做。第i 个人做第j 件工作产生的效益为ij c 。试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大。    对于给定的n件工作和n个人,计算最优分配方案和最差分配方案。

input

多组数据输入.每组输入第1 行有1 个正整数n<=50,表示有n件工作要分配给n 个人做。接下来的n 行中,每行有n 个整数Cij,1≤i≤n,1≤j≤n,表示第i 个人做第j件工作产生的效益为Cij 。

output

每组输出的最小总效益和最大总效益。

sample_input

52 2 2 1 22 3 1 2 42 0 1 1 12 3 4 3 33 2 1 2 1

sample_output

514
 二分图最佳匹配就是在满足匹配数最大的情况下,使费用取得最值的一类问题
二分图最佳匹配其实是费用流的一个特例,我们只要在原图中增加一个源点和汇点就成功的转换成费用流
模型,其转换方式与二分图最大匹配转最大流一样,新增加的边的费用都为0

#include <iostream>#include <cstdio>using namespace std;const int oo=1e5;const int mm=11111;const int mn=888;int node,src,dest,edge,SC[mn][mn];int ver[mm],flow[mm],cost[mm],next[mm];int head[mn],dis[mn],p[mn],q[mn],vis[mn];void prepare(int _node,int _src,int _dest){   node=_node,src=_src,dest=_dest;   for(int i=0;i<node;++i)head[i]=-1,vis[i]=0;   edge=0;}void addedge(int u,int v,int f,int c){   ver[edge]=v,flow[edge]=f,cost[edge]=c,next[edge]=head[u],head[u]=edge++;   ver[edge]=u,flow[edge]=0,cost[edge]=-c,next[edge]=head[v],head[v]=edge++;}bool spfa(){    int i,u,v,l,r=0,tmp;    for(i=0;i<node;i++) dis[i]=oo;    dis[q[r++]=src]=0;    p[src]=p[dest]=-1;    for(l=0;l!=r;(++l>=mn)?l=0:l)        for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])            if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i]))            {                dis[v]=tmp;//cout<<"u="<<u<<" v="<<v<<" tmp="<<tmp<<endl;                p[v]=i^1;                if(vis[v])  continue;                vis[q[r++]=v]=1;                if(r>=mn)   r=0;            }    return p[dest]>-1;}bool spfa1(){    int i,u,v,l,r=0,tmp;    for(i=0;i<node;i++) dis[i]=-oo;    dis[q[r++]=src]=0;    p[src]=p[dest]=-1;    for(l=0;l!=r;(++l>=mn)?l=0:l)        for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])            if(flow[i]&&dis[v=ver[i]]<(tmp=dis[u]+cost[i]))            {                dis[v]=tmp;//cout<<"u="<<u<<" v="<<v<<" tmp="<<tmp<<endl;                p[v]=i^1;                if(vis[v])  continue;                vis[q[r++]=v]=1;                if(r>=mn)   r=0;            }    return p[dest]>-1;}int Spfaflow(){    int i,ret=0,delta;    while(spfa())    {        for(i=p[dest],delta=oo;i>=0;i=p[ver[i]]){            if(flow[i^1]<delta) delta=flow[i^1];}           // cout<<"delta="<<delta<<endl;        for(i=p[dest];i>=0;i=p[ver[i]])            flow[i]+=delta,flow[i^1]-=delta;        ret+=delta*dis[dest];//cout<<"ret="<<ret<<endl;    }    return ret;}int SpfaFlow(){    int i,ret=0,delta;    while(spfa1())    {        for(i=p[dest],delta=oo;i>=0;i=p[ver[i]]){            if(flow[i^1]<delta) delta=flow[i^1];}           // cout<<"delta="<<delta<<endl;        for(i=p[dest];i>=0;i=p[ver[i]])            flow[i]+=delta,flow[i^1]-=delta;        ret+=delta*dis[dest];//cout<<"ret="<<ret<<endl;    }    return ret;}int main(){    int n,tot,i,j,a;    while(~scanf("%d",&n))    {        prepare(2*n+2,0,2*n+1);        for(i=1;i<=n;i++){            addedge(0,i,1,0);           // cout<<"from=0 to="<<i<<endl;        }        for(i=1;i<=n;i++)        {            for(j=1;j<=n;j++)            {                scanf("%d",&SC[i][j]);                addedge(i,n+j,oo,SC[i][j]);               // cout<<"from="<<i<<" to="<<n+j<<" a="<<a<<endl;            }        }        for(i=1;i<=n;i++){            addedge(n+i,2*n+1,1,0);           // cout<<"from="<<n+i<<" to="<<2*n+1<<endl;        }        printf("%d\n",Spfaflow());        prepare(2*n+2,0,2*n+1);        for(i=1;i<=n;i++){            addedge(0,i,1,0);            //cout<<"from=0 to="<<i<<endl;        }        for(i=1;i<=n;i++)        {            for(j=1;j<=n;j++)            {                addedge(i,n+j,oo,SC[i][j]);                //cout<<"from="<<i<<" to="<<n+j<<" a="<<a<<endl;            }        }        for(i=1;i<=n;i++){            addedge(n+i,2*n+1,1,0);            //cout<<"from="<<n+i<<" to="<<2*n+1<<endl;        }        printf("%d\n",SpfaFlow());    }    return 0;}



原创粉丝点击