【平面图最小割】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 } 

 

posted @ 2016-07-29 23:50  iiyiyi  阅读(621)  评论(0编辑  收藏  举报