顾客买猪问题
建图的方法:
当第i个猪圈第顾客K(不是每一个顾客都去打开每一个猪圈)一次被打开的时候, 就从超级源点连一条到顾客K的边, 权值为猪圈i里面猪的数量
当第i个猪圈不是是第一次被打开的时候, 那么就将上一个打开这个猪圈的人连到当前顾客, 权值为正无穷
将所有顾客都连一一条边倒超级汇点, 权值是顾客想买猪的数量
//SPA #include <cstring> #include <cstdio> #include <queue> #include <algorithm> #define CLR(arr, val) memset(arr, val, sizeof(arr)) #pragma warning(disable:4996) using namespace std; const int MaxV = 1003; const int MaxE = 10000 << 1; const int INF = 1e9; struct Graph { struct Vertex { int head; }V[MaxV]; struct Edge { int v, c, f, next; Edge(){} Edge(int v,int c, int f, int next):v(v), c(c), f(f), next(next){} }E[MaxE]; void init() { top = 0; CLR(V, -1); } void addEdge(int u, int v,int w) { E[top] = Edge(v, w, 0, V[u].head); V[u].head = top++; E[top] = Edge(u, 0, 0, V[v].head); V[v].head = top++; } int top; }; int h[MaxV]; //高度 int path[MaxV]; //回路 int gap[MaxV]; //gap优化 int cur[MaxV]; //当前弧优化 int s, t; int vexNum, edgeNum; Graph g; void setHeight() { CLR(gap, 0); CLR(h, -1); h[t] = 0; queue<int>Q; Q.push(t); while(!Q.empty()) { int top = Q.front(); gap[ h[top] ]++; for(int i = g.V[top].head; i != -1; i = g.E[i].next) { int v = g.E[i].v; if(h[v] == -1) { h[v] = h[top] + 1; Q.push(v); } } Q.pop(); } } int sap() { setHeight(); int maxFlow = 0, u = s; int flow = INF; for(int i = 0; i <= vexNum; i++) cur[i] = g.V[i].head; while(h[s] < vexNum) { int &i = cur[u]; for(; i != -1; i = g.E[i].next) { int v = g.E[i].v; if(g.E[i].c > g.E[i].f && h[u] == h[v] + 1) { u = v; path[v] = i; flow = min(flow, g.E[i].c - g.E[i].f); if(u == t) { while(u != s) { int j = path[u]; g.E[j].f += flow; g.E[j ^ 1].f -= flow; u = g.E[j ^ 1].v; } maxFlow += flow; flow = INF; } break; } } if(i == -1) { if(--gap[ h[u] ] == 0) break; int minH = vexNum - 1; cur[u] = g.V[u].head; for(int j = g.V[u].head; j != -1; j = g.E[j].next) if(g.E[j].c > g.E[j].f) minH = min(minH, h[g.E[j].v]); h[u] = minH + 1; ++gap[ h[u] ]; if(u != s) u = g.E[path[u] ^ 1].v; } } return maxFlow; } int N, M; int pagNum[1003]; //1000个猪圈, 猪圈里面猪的数量 int lastOpen[1003]; //1000个猪圈, lastopen[i] 是最后打开猪圈i的顾客 int main() { while(scanf("%d %d", &M, &N) != EOF) { g.init(); CLR(lastOpen, -1); s = 0, t = N + 1; vexNum = N + 2; for(int i = 1; i <= M; i++) scanf("%d", &pagNum[i]); for(int i = 1; i <= N; i++) { int A; scanf("%d", &A); while(A--) { int v; scanf("%d", &v); if(lastOpen[v] == -1) //第一次被打开 { g.addEdge(s, i, pagNum[v]); lastOpen[v] = i; } else { g.addEdge(lastOpen[v], i, INF); lastOpen[v] = i; } } int B; scanf("%d", &B); g.addEdge(i, t, B); } printf("%d\n", sap()); } return 0; } /* 2 2 2 2 2 1 2 1 1 2 10 */