(網路流)[ZJOI2009]假期的宿舍
阿新 • • 發佈:2018-12-21
https://www.luogu.org/problemnew/show/P2055 學校放假了 · · · · · · 有些同學回家了,而有些同學則有以前的好朋友來探訪,那麼住宿就是一個問題。比如 A 和 B 都是學校的學生,A 要回家,而 C 來看B,C 與 A 不認識。我們假設每個人只能睡和自己直接認識的人的床。那麼一個解決方案就是 B 睡 A 的床而 C 睡 B 的床。而實際情況可能非常複雜,有的人可能認識好多在校學生,在校學生之間也不一定都互相認識。我們已知一共有 n 個人,並且知道其中每個人是不是本校學生,也知道每個本校學生是否回家。問是否存在一個方案使得所有不回家的本校學生和來看他們的其他人都有地方住。
n<=50, t<=20. 建圖為人和床位分開,校外的人建一條由源點容量為1的邊,校內的人分兩種,如果不離校,建立一條自己到自己床位的邊;如果離校則建立一條到匯點的容量為1的邊。如果i和j有關係,因為每個人只能睡和自己有直接關係的人的床位,所以建一條由i人到j的床位的容量為1的邊。跑出最大流判斷需要呆在學校的人和流量相等是否即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pi; const int maxn = 50 * 50 + 10; const int INF = 0x3f3f3f3f; struct Edge { int from, to, cap, flow; Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {} }; struct EdmondKarp { int n, m; vector<Edge> edges; vector<int> G[maxn]; int a[maxn], p[maxn]; void init(int n) { for (register int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from, int to, int cap) { edges.push_back(Edge(from, to, cap, 0)); edges.push_back(Edge(to, from, 0, 0)); m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } int Maxflow(int s, int t) { int flow = 0; for (;;) { memset(a, 0, sizeof(a)); queue<int> Q; Q.push(s); a[s] = INF; while (!Q.empty()) { int x = Q.front(); Q.pop(); for (register int i = 0; i < G[x].size(); i++) { Edge &e = edges[G[x][i]]; if (!a[e.to] && e.cap > e.flow) { p[e.to] = G[x][i]; a[e.to] = min(a[x], e.cap - e.flow); Q.push(e.to); } } if (a[t]) break; } if (!a[t]) break; for (int u = t; u != s; u = edges[p[u]].from) { edges[p[u]].flow += a[t]; edges[p[u] ^ 1].flow -= a[t]; } flow += a[t]; } return flow; } }; int t, n, x, vis[maxn]; int main() { register int i, j; scanf("%d", &t); while(t--) { EdmondKarp ek; memset(vis, 0, sizeof(vis)); int cnt = 0; scanf("%d", &n); ek.init(2 * n + 2); for (i = 1; i <= n; i++) { scanf("%d", &x); if(x == 0) ek.AddEdge(0, i, 1), cnt++; else { ek.AddEdge(n + i, 2 * n + 1, 1); vis[i] = 1; } } for (i = 1; i <= n; i++) { scanf("%d", &x); if(vis[i]) { if(x == 0) { ek.AddEdge(0, i, 1); ek.AddEdge(i, i + n, 1); cnt++; } } } for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { scanf("%d", &x); if(!x) continue; ek.AddEdge(i, j + n, 1); } } printf("%s\n", ek.Maxflow(0, 2 * n + 1) == cnt ? "^_^" : "T_T"); } }