经典的最大流模型,按照下列规则建出网络图,然后做一次最大流即可。
• 每个顾客分别用一个结点来表示。
• 对于每个猪圈的第一个顾客,从源点向他连一条边,容量就是该猪圈里的猪的初始数量。如果从源点到一名顾客有多条边,则可以把它们合并成一条,容量相加。
• 对于每个猪圈,假设有 n 个顾客打开过它,则对所有整数 i∈[1, n),从该猪圈的第 i 个顾客向第 i + 1 个顾客连一条边,容量为∞。
• 从各个顾客到汇点各有一条边,容量是各个顾客能买的数量上限。
代码:
#include<cstdio> #include<cstring> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 100 + 10; const int maxm = 1000 + 10; int cur[maxn],dis[maxn],gap[maxn],pre[maxn],flow[maxn]; int tmp[maxm],last[maxm]; int cap[maxn][maxn]; bool flag[maxm]; int n,m; int s,t,nodenum; void init() { freopen("poj1149.in","r",stdin); freopen("poj1149.out","w",stdout); } inline int min(int a,int b) { return a < b ? a : b; } void readdata() { memset(flag,false,sizeof(flag)); scanf("%d%d",&m,&n); nodenum = n + 2; s = 0;t = n + 1; for(int i = 1;i <= m;i++) { scanf("%d",&tmp[i]); } for(int i = 1;i <= n;i++) { int cnt; scanf("%d",&cnt); for(int j = 1;j <= cnt;j++) { int p; scanf("%d",&p); if(!flag[p]) { flag[p] = true; cap[s][i] += tmp[p]; last[p] = i; } else { cap[last[p]][i] = inf; last[p] = i; } } int limit; scanf("%d",&limit); cap[i][n+1] = limit; } } int sap() { memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); int u = pre[s] = s,maxflow = 0,aug = inf; gap[0] = nodenum; while(dis[s] < nodenum) { loop: for(int v = cur[u];v < nodenum;v++) { if(cap[u][v] && dis[u] == dis[v] + 1) { cur[u] = v; aug = min(aug,cap[u][v]); pre[v] = u; u = v; if(v == t) { maxflow += aug; for(u = pre[u];v != s;v = u,u = pre[u]) { cap[u][v] -= aug; cap[v][u] += aug; } aug = inf; } goto loop; } } int mind = n + 1; for(int v = 1;v < nodenum;v++) { if(cap[u][v] && (mind > dis[v])) { cur[u] = v; mind = dis[v]; } } if((--gap[dis[u]]) == 0)break; gap[dis[u] = mind + 1]++; u = pre[u]; } return maxflow; } void solve() { printf("%d",sap()); } int main() { init(); readdata(); solve(); return 0; }