分配(dispatch)

題目大意:有兩種人,分別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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章