hdu 4975 A simple Gaussian elimination problem 最大流+找环
原题链接
http://acm.hdu.edu.cn/showproblem.php?pid=4975
这是一道很裸的最大流,将每个点(i,j)看作是从Ri向Cj的一条容量为9的边,从源点除法连接每个Ri,再从每个Ci连接至汇点。如若最大流不是滿流,则问题无解。这道题的关键就是在于如何判断是否有多解。考虑这样一个事实,若残余网络上有多个点构成一个环,那么流量可在这个环上调整,某条边上多余的流量可以被环上的其他的边弥补回来。所以如果残余网络上存在一个边数大于2的环,那么问题则是多解。我判断是否有环的方法是Tarjan。
详见代码:
#include<iostream> #include<stack> #include<vector> #include<cstring> #include<algorithm> #include<queue> #define MAX_V 2015 #define MAX_N 10004 #define INF 2500005 using namespace std; struct edge{int to,cap,rev;}; vector<edge> G[MAX_N]; int level[MAX_V]; int iter[MAX_V]; void add_edge(int from,int to,int cap) { G[from].push_back((edge) {to, cap, G[to].size()}); G[to].push_back((edge) {from, 0, G[from].size() - 1}); } void bfs(int s) { memset(level, -1, sizeof(level)); queue<int> que; level[s] = 0; que.push(s); while (!que.empty()) { int v = que.front(); que.pop(); for (int i = 0; i < G[v].size(); i++) { edge &e = G[v][i]; if (e.cap > 0 && level[e.to] < 0) { level[e.to] = level[v] + 1; que.push(e.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 &e = G[v][i]; if (e.cap > 0 && level[v] < level[e.to]) { int d = dfs(e.to, t, min(f, e.cap)); if (d > 0) { e.cap -= d; G[e.to][e.rev].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, INF)) > 0) { flow += f; } } } bool vis[MAX_N]; int low[MAX_N],dfn[MAX_N],tot=0; bool inStack[MAX_N]; stack<int> st; bool exitCircle=false; void Tarjan(int u) { if (exitCircle)return; vis[u] = 1; inStack[u] = 1; st.push(u); low[u] = dfn[u] = ++tot; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].to; if (G[u][i].cap == 0)continue; if (!vis[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if (inStack[v]) low[u] = min(low[u], dfn[v]); } if (dfn[u] == low[u]) { int cnt = 0; while (inStack[u]) { if (st.empty())break; cnt++; //cout << st.top() << " "; inStack[st.top()] = 0; st.pop(); } if (cnt > 2)exitCircle = true; //cout << endl; } } int T; int N,M; int main() { cin.sync_with_stdio(false); cin >> T; int cas = 0; while (T--) { int sum = 0; cin >> N >> M; for(int i=0;i<N+M+3;i++)G[i].clear(); memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); tot=0; memset(inStack,0,sizeof(inStack)); exitCircle=false; while(st.size())st.pop(); for (int i = 0; i < N; i++) { int a; cin >> a; sum += a; add_edge(0, i + 1, a); } for (int i = 0; i < M; i++) { int a; cin >> a; add_edge(N + i + 1, N + M + 1, a); } for (int i = 1; i <= N; i++) for (int j = 1; j <= M; j++) add_edge(i, j + N, 9); int flow = max_flow(0, N + M + 1); cout << "Case #" << ++cas << ": "; if (flow != sum) { cout << "So naive!" << endl; continue; } for (int i = 0; i <= N + M + 1; i++)if (!vis[i])Tarjan(i); if (exitCircle)cout << "So young!" << endl; else cout << "So simple!" << endl; } return 0; }