这个题的意思是有M个猪圈, N个人, 每个人按次序可以访问一些猪圈并可以买走一定数量的猪, 并且一个人用自己所拥有的猪圈钥匙打开猪圈后这些猪可以重新分配到已经打开的猪圈中, 问你可以买的最多的猪是多少个?强烈推荐看这个博文, 非常感谢博主
http://ycool.com/post/zhhrrm6
代码如下:
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <queue> using namespace std; const int inf = 0x3fffffff; const int maxn = 2000+10; struct Dinic { int n; struct edge { int from, to, cap; }; vector<int> G[maxn]; vector<edge> e; int level[maxn], iter[maxn]; void init() { for(int i=0; i<=n; i++) G[i].clear(); e.clear(); } void add_edge(int u, int v, int cap) { e.push_back((edge){u, v, cap}); e.push_back((edge){v, u, 0}); int m = e.size(); G[u].push_back(m-2); G[v].push_back(m-1); } void bfs(int s) { memset(level, -1, sizeof(level)); queue<int> que; level[s] = 0; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); for(int i=0; i<G[u].size(); i++) { edge &te = e[G[u][i]]; if(te.cap>0 && level[te.to]<0) { level[te.to] = level[u] + 1; que.push(te.to); } } } } int dfs(int v, int t, int f) { if(v == t) return f; for(int &i=iter[v]; i<G[v].size(); i++) { edge& tpe = e[G[v][i]]; if(tpe.cap>0 && level[v]<level[tpe.to]) { int d = dfs(tpe.to, t, min(f, tpe.cap)); if(d > 0) { tpe.cap -= d; e[G[v][i]^1].cap += d; return d; } } } return 0; } int max_flow(int s, int t) { int flow = 0; for(;;) { bfs(s); if(level[t]<0) return flow; memset(iter, 0, sizeof(iter)); int f; while((f=dfs(s, t, 0x3fffffff)) > 0) flow += f; } return flow; } }di; int pignum[1000+10]; int f[1000+10]; //i猪圈最后访问的人是哪一个 int G[105][105]; int main() { int M, N; scanf("%d%d", &M, &N); di.n = N+2; //0超级源点 N+1超级汇点 di.init(); for(int i=1; i<=M; i++) scanf("%d", &pignum[i]); memset(f, -1, sizeof(f)); memset(G, -1, sizeof(G)); for(int i=1; i<=N; i++) { int v = i; int keynum; scanf("%d", &keynum); for(int i=0; i<keynum; i++) { int u = 0, t, cap; scanf("%d", &t); if(f[t] == -1) { cap = pignum[t]; G[u][v] = (G[u][v]==-1?cap:G[u][v]+cap); f[t] = v; } else { u = f[t]; cap = inf; G[u][v] = inf; f[t] = v; } } int ndnum; scanf("%d", &ndnum); G[v][N+1] = ndnum; } for(int i=0; i<N+2; i++) for(int j=0; j<N+2; j++) if(G[i][j] != -1) di.add_edge(i, j, G[i][j]); printf("%d\n", di.max_flow(0, N+1)); return 0; }