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;
}
* 生而自由 爱而无畏 *