【JZOJ3990】分配
###Description
【JZOJ3990】分配
###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]);
}