【JZOJ3990】分配

Description

为了增加军队的战斗力,D国建立了两所重要的军事院校A和B,每年为军队培养人才。这两所军校所培养的学生最终都分配到两个重要的军事科研院X和Y中。
已知今年A和B分别毕业nA和nB个毕业生,A校的毕业生从1到nA编号,B校的毕业生从nA + 1到nA + nB编号。他们每个人都对两个科研院有自己的评分,编号为i的毕业生对X和Y的评分分别为ui和vi。评分是一个整数,可能一个毕业生不喜欢某一个科研院,因此他的评分可能是负数。
在工作的时候,如果同一个学校的毕业生在同一个研究院工作,他们会很默契的配合,如果两个毕业生a和b来自不同的院校,他们需要花费Cab的磨合成本。
栋栋今年负责两校毕业生的分配,他想知道,他怎么分配毕业生,能使得最终所有毕业生对自己分配到的院校的评分和,再减去在一起工作的不同院校的磨合成本最高。

Solution

很明显的二元关系模型。

这里要求最大评分,那么考虑把所有评分加起来,减去最小代价。这里院校相同就会产生代价,那我们把边换一下,源汇交换一下即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
using namespace std;
const int N=220,M=42000,_=1000,inf=1e9;
int to[M<<2],nx[M<<2],ls[N<<1],num=1;
int vl[M<<2];
int S,T;
void link(int u,int v,int w){
    to[++num]=v,nx[num]=ls[u],ls[u]=num;
    vl[num]=w;
    to[++num]=u,nx[num]=ls[v],ls[v]=num;
    vl[num]=0;
}
int vis[N<<1];
void dfs(int x){
    vis[x]=1;
    rep(i,x) if(vl[i] && !vis[to[i]]) dfs(to[i]);
}
int dl[N<<1],h[N<<1];
int an[N<<1];
bool bfs(){
    memset(h,0,sizeof(h));
    int l=0,r=1;
    h[dl[1]=S]=1;
    while(l<r){
        int x=dl[++l];
        rep(i,x){
            int v=to[i];
            if(vl[i] && !h[v]) h[v]=h[x]+1,dl[++r]=v;
        }
    }
    return h[T];
}
int flow(int x,int t){
    if(x==T) return t;
    int fl=t;
    rep(i,x){
        int v=to[i];
        if(vl[i] && h[x]+1==h[v]){
            int tmp=flow(to[i],min(t,vl[i]));
            if(tmp){
                vl[i]-=tmp,vl[i^1]+=tmp,t-=tmp;
                if(!t) break;
            }
        }
    }
    if(fl==t) h[x]=-1;
    return fl-t;
}
int main()
{
    int n,m,o;
    scanf("%d %d",&n,&m);
    S=n+m+1,T=S+1;
    int ans=0;
    fo(i,1,n) scanf("%d",&o),ans+=o,link(S,i,o+_);
    fo(i,1,m) scanf("%d",&o),ans+=o,link(i+n,T,o+_);
    fo(i,1,n) scanf("%d",&o),ans+=o,link(i,T,o+_);
    fo(i,1,m) scanf("%d",&o),ans+=o,link(S,i+n,o+_);
    fo(i,1,n)
    fo(j,1,m){
        scanf("%d",&o);
        link(i,j+n,o),link(j+n,i,o);
    }
    int tmp=0;
    while(bfs())
    tmp+=flow(S,inf);
    printf("%d\n",ans+_*(n+m)-tmp);
    dfs(S);
    fo(i,1,n) an[i]=2-vis[i];
    fo(i,n+1,n+m) an[i]=vis[i]+1;
    fo(i,1,n+m) printf("%d ",an[i]);
}

猜你喜欢

转载自blog.csdn.net/sadnohappy/article/details/78996313