1001(網路流/平面圖轉對偶圖求最短路)
阿新 • • 發佈:2019-01-04
題意:有個方格,求從(1,1)到(n,m)的最小割
題解:有兩種方法,第一種:使用dinic演算法,但是需要有個優化就是當每次增廣時,如果一旦哪條路增廣失敗,那麼就把這條路直接賦值為-1,把它堵死,這樣優化可以達到很高。
附上第一種程式碼:(使用白書上的dinic演算法呢,可以過,但是時間還是相當高的,最好還是使用鏈式前向星進行儲存)
#include<bits/stdc++.h> using namespace std; const int INF=0x3f3f3f3f; const int MAX_V=1e6+50; struct edge{ int to,cap,rev; edge(int _to,int _cap,int _rev):to(_to),cap(_cap),rev(_rev){} }; vector<edge>G[MAX_V]; int level[MAX_V]; int iter[MAX_V]; int n,m; 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,cap,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; }else{//此處為優化 level[e.to]=-1; } } } 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; } } } inline int gethash(int i,int j) { return (i-1)*m+j; } int main() { scanf("%d%d",&n,&m); int s,t,temp; s=1; t=gethash(n,m); for(int i=1;i<=n;i++){ for(int j=1;j<m;j++){ scanf("%d",&temp); add_edge(gethash(i,j),gethash(i,j+1),temp); } } for(int i=1;i<n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&temp); add_edge(gethash(i,j),gethash(i+1,j),temp); } } for(int i=1;i<n;i++){ for(int j=1;j<m;j++){ scanf("%d",&temp); add_edge(gethash(i,j),gethash(i+1,j+1),temp); } } int ans=max_flow(s,t); printf("%d\n",ans); return 0; }
主要得掌握平面圖轉化為對偶圖的思想以及做法:
然後就是建立這個非常複雜的圖,最後跑一遍dijkstra演算法即可
附上程式碼:
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cctype> #include <vector> #include <cstring> using namespace std; inline void read(int &x) { x = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) x = x * 10 + c - '0', c = getchar(); } #define MAXN 2000010 struct node{ int to, va; node(int a, int b) { to = a, va = b; } }; vector<node> v[MAXN]; inline void add_edge(int f, int t, int w) { v[f].push_back(node(t, w)); v[t].push_back(node(f, w)); } bool vis[MAXN]; int st, ed; int dis[MAXN]; int SPFA() { memset(dis, 0x3f, sizeof dis); vis[st] = 1; queue<int> q; q.push(st); dis[st] = 0; while(!q.empty()) { int tmp = q.front(); //cout<<tmp<<" "; q.pop(); vis[tmp] = 0; for(int i = 0; i < v[tmp].size(); ++i) { int o = v[tmp][i].to; //cout<<o<<" "; if(dis[o] > dis[tmp] + v[tmp][i].va) { dis[o] = dis[tmp] + v[tmp][i].va; if(!vis[o]) q.push(o), vis[o] = 1; } } } return dis[ed]; } int n, m; inline void getheng(int i, int j, int k) { if(i == 1) add_edge(st, j, k); else if(i == n) add_edge((2 * (n - 1) - 1) * (m - 1) + j, ed, k); else add_edge((2 * (i - 1) - 1) *(m - 1) + j, 2 * (i - 1) * (m - 1) + j, k); } inline void getshu(int i, int j, int k) { if(j == 1) add_edge((i * 2 - 1) * (m - 1) + 1, ed, k); else if(j == m) add_edge(st, 2 * i * (m - 1) - (m - 1), k); else add_edge((i - 1) * 2 * (m - 1) + j - 1, ((i - 1) * 2 + 1) * (m - 1) + j, k); } inline void getxie(int i, int j, int k) { add_edge((i - 1) * 2 * (m - 1) + j, (i - 1) * 2 * (m - 1) + (m - 1) + j, k); } int main() { read(n), read(m); st = (n - 1) * (m - 1) * 2 + 1, ed = (n - 1) * (m - 1) * 2 + 2; int x; for(int i = 1; i <= n; ++i) { for(int j = 1; j < m; ++j) read(x), getheng(i, j, x); } for(int i = 1; i < n; ++i) { for(int j = 1; j <= m; ++j) read(x), getshu(i, j, x); } for(int i = 1; i < n; ++i) { for(int j = 1; j < m; ++j) read(x), getxie(i, j, x); } /*for(int i = 1; i <= ((n - 1) * (m - 1) * 2 + 2); ++i) { for(int j = 0; j < v[i].size(); ++j) cout<<v[i][j].to<<" "; cout<<endl; }*/ cout<<SPFA()<<endl; return 0; }