[POJ1149][SPOJ4063]PIGS(最大流)

[POJ1149][SPOJ4063]PIGS(最大流)

题面

分析

很妙的网络流建图套路。

注意到我们只能交换客户打开过的猪圈里的猪。那么相当于可以通过顾客来中转猪。体现到建图上就是:
我们把每一个顾客看成一个点。对于每个猪圈,从原点向打开它的第一个顾客连边,容量为初始猪数量\(a_i\),表示最多可以提供的量.每个顾客向汇点连容量为需求量\(b_j\)的边。对于同一个猪圈的所有顾客,我们将它按时间顺序连起来,容量为\(+\infin\)。比如从顾客\(j\)向顾客\(j+1\)连边,就可以表示顾客\(j\)打开猪圈\(i\)买完猪后,将\(i\)中的猪换到\(j+1\)打开的猪圈中。

网络最大流即为答案

代码

//https://www.luogu.com.cn/problem/SP4063
#include<iostream>
#include<cstdio>
#include<cstring> 
#include<vector>
#include<queue> 
#define INF 0x3f3f3f3f 
#define maxn 10000
#define maxm 100000
using namespace std;
int n,m;
int a[maxn+5],b[maxn+5];
vector<int>p[maxn+5];

struct edge{
	int from;
	int to;
	int next;
	int flow;
}E[maxm*2+5];
int sz=1;
int head[maxn+5];
void add_edge(int u,int v,int w){
//	printf("%d->%d %d\n",u,v,w);
	sz++;
	E[sz].from=u;
	E[sz].to=v;
	E[sz].next=head[u];
	E[sz].flow=w;
	head[u]=sz;
	sz++;
	E[sz].from=v;
	E[sz].to=u;
	E[sz].next=head[v];
	E[sz].flow=0;
	head[v]=sz;
}
int deep[maxn+5];
bool bfs(int s,int t){
	for(int i=s;i<=t;i++) deep[i]=0;
	queue<int>q;
	q.push(s);
	deep[s]=1;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=head[x];i;i=E[i].next){
			int y=E[i].to; 
			if(E[i].flow&&!deep[y]){
				deep[y]=deep[x]+1;
				q.push(y);
			}
		}
	}
	return deep[t]>0;
} 
int dfs(int x,int t,int minf){
	if(x==t) return minf;
	int rest=minf,k;
	for(int i=head[x];i;i=E[i].next){
		int y=E[i].to;
		if(E[i].flow&&deep[y]==deep[x]+1){
			k=dfs(y,t,min(rest,E[i].flow));
			E[i].flow-=k;
			E[i^1].flow+=k;
			rest-=k; 
			if(k==0) deep[y]=0;
			if(rest==0) break;
		}
	}
	return minf-rest;
}
int dinic(int s,int t){
	int ans=0,now=0;
	while(bfs(s,t)){
		while((now=dfs(s,t,INF))) ans+=now;
	}
	return ans;
} 
 
int main(){
	scanf("%d %d",&m,&n);
	for(int i=1;i<=m;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++){
		int k,x;
		scanf("%d",&k);
		for(int j=1;j<=k;j++){
			scanf("%d",&x);
			p[x].push_back(i);
		}
		scanf("%d",&b[i]);
	}
	int s=0,t=n+1;
	for(int i=1;i<=m;i++){
		for(int j=0;j<(int)p[i].size();j++){
			if(j==0) add_edge(s,p[i][j],a[i]);
			else add_edge(p[i][j-1],p[i][j],INF);
		}
	}
	for(int i=1;i<=n;i++) add_edge(i,t,b[i]);
	printf("%d\n",dinic(s,t));
}
posted @ 2020-03-29 20:13  birchtree  阅读(116)  评论(0编辑  收藏  举报