POJ1149 PIGS

题意

你有\(m\)个猪圈,第\(i\)个猪圈初始有\(a_i\)头猪。
依次到来\(n\)个顾客,每个顾客会打开几个猪圈,你可以随意调换放置这些猪圈中的猪,再卖给这个顾客\(b_i\)头猪。
求最大化总卖猪数量。
\(n \leq 100,m \leq 1000\)

思路

做法很多。
考虑最大流。把猪圈和顾客都看成点。初始从源点向\(i\)猪圈连流量为\(a_i\)的边。
重新放猪可以视为把这些猪寄存在这个顾客手中,省些力,让顾客去放置。那么新来的顾客可以直接从原猪圈买,也可以从上一个打开这个猪圈的顾客手中买(那个顾客寄存着剩余的猪),将买主与指定猪圈及上一位顾客连流量为无穷大的边(原本应该向每个打开过的连边,但其实只向上一个连即可保证尽量多的猪都能卖出,可以减少边数)
卖猪即从顾客向汇点连流量为\(b_i\)边。

#include <cstdio>
#include <queue>
#include <cstring>
const int N=1000005,INF=1000000000;
using namespace std;
queue <int> q;
int m,n,x,k,a[1005],to[N],last[2005],Next[N],edge,t,deep[2005],w[N],ans,s;
void add(int x,int y,int z){
	to[++edge]=y;
	Next[edge]=last[x];
	last[x]=edge;
	w[edge]=z;
}
bool bfs(int s){
	memset(deep,0,sizeof(deep));
	q.push(s);
	deep[s]=1;
	while (!q.empty()){
		int x=q.front();
		q.pop();
		for (int i=last[x];i;i=Next[i])
		if (w[i] && deep[to[i]]==0){
			q.push(to[i]);
			deep[to[i]]=deep[x]+1;
		}
	}
	if (deep[t]) return true;
	return false;
}
int c(int x){
	return x&1?x+1:x-1; 
}
int dfs(int x,int now){
	if (x==t) return now;
	for (int i=last[x];i;i=Next[i])
		if (deep[to[i]]>deep[x] && w[i]){
			int di=dfs(to[i],min(now,w[i]));
			if (di){
				w[i]-=di;
				w[c(i)]+=di;
				return di;
			}
		}
	return 0;
}
int main(){
	scanf("%d%d",&m,&n);
	t=n+m+1,s=n+m+2;
	for (int i=1;i<=m;i++){
		scanf("%d",&x);
		add(s,i,x);
		add(i,s,0);
	}
	for (int i=1;i<=n;i++){
		scanf("%d",&k);
		for (int j=1;j<=k;j++){
			scanf("%d",&x);
			if (a[x]>0) add(a[x]+m,i+m,INF),add(i+m,a[x]+m,0);
			a[x]=i;
			add(x,i+m,INF),add(i+m,x,0);
		}
		scanf("%d",&x);
		add(i+m,t,x),add(t,i+m,0);	
	}
	while (bfs(s))
		while (int di=dfs(s,INF)) ans+=di;
	printf("%d",ans);
	return 0;
} 
posted @ 2019-07-09 07:27  flyfeather  阅读(102)  评论(0编辑  收藏  举报