【平面图最小割】BZOJ2007-[NOI2010]海拔
【题目大意】
城市被东西向和南北向的主干道划分为n×n个区域,包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路。现得到了每天每条道路两个方向的人流量。每一个交叉路口都有海拔,每向上爬h的高度,就需要消耗h的体力。如果是下坡的话,则不需要耗费体力。城市西北角的交叉路口海拔为0,东南角的交叉路口海拔为1。现在知道每条路两个方向的人流量,在最理想的情况下(即你可以任意假设其他路口的海拔高度),求每天所有人爬坡所消耗的总体力和的最小值。
【思路】
显然是一个平面图最小割,最基础的平面图最小割可以参考BZOJ1002狼爪兔子。转成对偶图,跑Dijkstra+堆优化。
问题在于,边是有向的(即两个方向的人流量是不同的),北南、南北、东西、西东应该如何对应对偶图中的方向呢?画了张图(我人生所有的画图都要献给平面图了……)
a
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 #define S 0 8 #define T (n*n)+1 9 using namespace std; 10 typedef long long ll; 11 const int MAXN=550*550; 12 const ll INF=1000000000; 13 struct edge 14 { 15 int fr,to,len; 16 }; 17 vector<edge> E[MAXN]; 18 int n; 19 20 void addedge(int u,int v,int w) 21 { 22 E[u].push_back((edge){u,v,w}); 23 } 24 25 int dijkstra() 26 { 27 priority_queue<pair<ll,ll>,vector<pair<ll,ll> >,greater<pair<ll,ll> > > que; 28 ll dis[MAXN],vis[MAXN]; 29 memset(vis,0,sizeof(vis)); 30 for (int i=S+1;i<=T;i++) dis[i]=INF; 31 dis[S]=0; 32 que.push(make_pair<ll,ll>(0,S)); 33 while (!que.empty()) 34 { 35 int head=que.top().second;que.pop(); 36 if (!vis[head]) 37 { 38 vis[head]=1; 39 for (int i=0;i<E[head].size();i++) 40 { 41 edge Edge=E[head][i]; 42 if (!vis[Edge.to] && dis[Edge.to]>dis[Edge.fr]+Edge.len) 43 { 44 dis[Edge.to]=dis[Edge.fr]+Edge.len; 45 que.push(make_pair<ll,ll>(dis[Edge.to],Edge.to)); 46 } 47 } 48 } 49 } 50 return (dis[T]); 51 } 52 53 54 void init() 55 { 56 scanf("%d",&n); 57 int t; 58 for (int i=1;i<=n+1;i++) 59 for (int j=1;j<=n;j++) 60 { 61 scanf("%d",&t); 62 if (i==1) addedge((i-1)*n+j,n*n+1,t); 63 else if (i==n+1) addedge(0,(i-2)*n+j,t); 64 else addedge((i-1)*n+j,(i-2)*n+j,t); 65 } 66 67 for (int i=1;i<=n;i++) 68 for (int j=0;j<=n;j++) 69 { 70 scanf("%d",&t); 71 if (j==0) addedge(0,(i-1)*n+j+1,t); 72 else if (j==n) addedge(i*n,n*n+1,t); 73 else addedge((i-1)*n+j,(i-1)*n+j+1,t); 74 } 75 76 for (int i=1;i<=n+1;i++) 77 for (int j=1;j<=n;j++) 78 { 79 scanf("%d",&t); 80 if (i==1) addedge(n*n+1,(i-1)*n+j,t); 81 else if (i==n+1) addedge((n-1)*n+j,0,t); 82 else addedge((i-2)*n+j,(i-1)*n+j,t); 83 } 84 85 for (int i=1;i<=n;i++) 86 for (int j=0;j<=n;j++) 87 { 88 scanf("%d",&t); 89 if (j==0) addedge((i-1)*n+j+1,0,t); 90 else if (j==n) addedge(n*n+1,(i-1)*n+j,t); 91 else addedge((i-1)*n+j+1,(i-1)*n+j,t); 92 } 93 94 } 95 96 int main() 97 { 98 init(); 99 printf("%d\n",dijkstra()); 100 return 0; 101 }