題目大意:有兩種人,分別Na,Nb個,兩個地方,每個人都要去一個地方,每個人到一個地方都可以獲得一個權值(絕對值小於1000),如果不同的一種人去了同一個地方,需要減掉一個權值c[i][j](大於等於0) ,求最大的權值還有在權值最大的情況下每個人去了哪裏 Na,Nb<=200
這題很神,首先要權值ans=w(去一個地方獲得的)-c(因爲兩種不同的人減去的)最大,我們可以讓-ans=c-w
這樣就只要讓-ans最小就OK了,因爲(-w)有正有負,所以就都先加上一個值,最後在減去就OK了,於是就是讓-ans=c+(-w)最小
這就可以用最小割來做了具體來說,X種人在S集是去A地,T集是去B地,Y種人是在S集去B地,T集去A地,然後就可以連邊了。。。
至於方案就看最後的每個點在S集還是T集,在結合上面的定義就OK了
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=444,maxm=100011,inf=~0u>>1,aw=1024;
inline int read(){
int x=0; char ch=getchar(); bool ok=0;
while (!isdigit(ch) && ch!='-') ch=getchar();
if (ch=='-') ch=getchar(),ok=1;
for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return ok?-x:x;
}
int tot=1,now[maxn],pre[maxm],son[maxm],v[maxm];
void add(int a,int b,int c){pre[++tot]=now[a]; now[a]=tot; son[tot]=b; v[tot]=c;}
void cc(int a,int b,int c,int d=0){add(a,b,c); add(b,a,d?c:0);}
int n,m,st,ed;
void init(){
n=read(); m=read(); st=n+m+1; ed=st+1;
for (int i=1;i<=n;++i) cc(st,i,aw-read()); for (int i=1;i<=m;++i) cc(i+n,ed,aw-read());
for (int i=1;i<=n;++i) cc(i,ed,aw-read()); for (int i=1;i<=m;++i) cc(st,i+n,aw-read());
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) cc(i,n+j,read(),1);
}
int dep[maxn];
bool bfs(){
memset(dep,0,sizeof(dep)); dep[st]=1;
int t=0,w=1; static int q[maxn]; q[1]=st;
while (t++<w){
for (int p=now[q[t]];p;p=pre[p]) if (!dep[son[p]] && v[p])
dep[q[++w]=son[p]]=dep[q[t]]+1;
if (dep[ed]) return 1;
}
return 0;
}
int find(int x,int f){
if (x==ed) return f; int ans=0;
for (int p=now[x];p;p=pre[p]) if (dep[son[p]]>dep[x] && v[p]){
int k=find(son[p],min(f,v[p]));
v[p]-=k; v[p^1]+=k; ans+=k; f-=k;
if (!f) return ans;
}
dep[x]=0; return ans;
}
int zg(){int ans=0; while (bfs()) ans+=find(st,inf); return ans;}
void work(){
printf("%d\n",1024*(n+m)-zg());
bfs(); for (int i=1;i<=n;++i) if (dep[i]) printf("2 ");else printf("1 ");
for (int i=1;i<=m;++i) if (dep[i+n]) printf("1 ");else printf("2 ");
}
int main(){
init();
work();
return 0;
}