P4001 [BJOI2006]狼抓兔子
阿新 • • 發佈:2018-07-25
反向 什麽 最小割 char turn bool 完成 如果 void
網絡流快樂地跑。。。
這道題就是要求這個無向圖的最小割。
根據最小割最大流定理,我們求個最大流就好了。
但是數據巨大。一百萬個點,我們看上去就有2996001條邊。
這個時候,如果按照網絡流做法,建反向邊的話,需要11984004條邊,MLE。
其實我就沒做過無向圖的網絡流。。。
結論:無向圖網絡流,只要兩條邊捆綁在一起就可以了,互相為反向邊。
為什麽有向圖的時候反向邊邊權為0,而這裏不為0?
無向圖有兩條邊,你必須加上去。有向圖壓根就沒有這條邊,只是給你一個反悔的機會而已,是個中介的邊。
所以建上5992002條邊,跑一個有當前弧優化的dinic,直接完成。
代碼:
#include<cstdio> #include<cstring> #include<algorithm> const int maxn = 1000005, INF = 0x7f7f7f7f; struct Edges { int next, to, weight; } e[maxn * 12]; int head[maxn], tot = 1; int n, m, s, t; int dep[maxn]; int cur[maxn]; int queue[maxn << 1], front, rear; int id(int x, int y) { return (y - 1) * m + x; } int read() { int ans = 0, s = 1; char ch = getchar(); while(ch > ‘9‘ || ch < ‘0‘) { if(ch == ‘-‘) s = -1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) { ans = ans * 10 + ch - ‘0‘; ch = getchar(); } return s * ans; } void link(int u, int v, int w) { e[++tot] = (Edges){head[u], v, w}; head[u] = tot; } void addEdges(int u, int v, int w) { link(u, v, w); link(v, u, 0); link(v, u, w); link(u, v, 0); } bool bfs() { memset(dep, 0, sizeof(dep)); front = rear = 0; dep[s] = 1; queue[rear++] = s; while(front < rear) { int u = queue[front++]; for(int i = head[u]; i; i = e[i].next) { int v = e[i].to; if(!dep[v] && e[i].weight > 0) { dep[v] = dep[u] + 1; queue[rear++] = v; } } } return dep[t]; } int dfs(int u, int flow) { if(u == t) return flow; for(int &i = cur[u]; i; i = e[i].next) { int v = e[i].to; if(dep[v] == dep[u] + 1 && e[i].weight > 0) { int di = dfs(v, std::min(flow, e[i].weight)); if(di > 0) { e[i].weight -= di; e[i ^ 1].weight += di; return di; } } } return 0; } int dinic() { int ans = 0; while(bfs()) { for(int i = 1; i <= t; i++) cur[i] = head[i]; while(int temp = dfs(s, INF)) ans += temp; } return ans; } int main() { n = read(), m = read(); for(int i = 1; i <= n; i++) { for(int j = 1; j < m; j++) { int weight = read(); //printf("%d %d\n", id(j, i), id(j + 1, i)); addEdges(id(j, i), id(j + 1, i), weight); } } for(int i = 1; i < n; i++) { for(int j = 1; j <= m; j++) { int weight = read(); //printf("%d %d\n", id(j, i), id(j, i + 1)); addEdges(id(j, i), id(j, i + 1), weight); } } for(int i = 1; i < n; i++) { for(int j = 1; j < m; j++) { int weight = read(); //printf("%d %d\n", id(j, i), id(j + 1, i + 1)); addEdges(id(j, i), id(j + 1, i + 1), weight); } } s = 1; t = n * m; printf("%d\n", dinic()); return 0; }
P4001 [BJOI2006]狼抓兔子