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]);
}