BZOJ2007: [Noi2010]海拔

2007: [Noi2010]海拔

Time Limit: 20 Sec  Memory Limit: 552 MB
Submit: 2684  Solved: 1291
[Submit][Status][Discuss]

Description

YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域。简单起见,可以将YT市看作一个
正方形,每一个区域也可看作一个正方形。从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路
(简称道路),每条双向道路连接主干道上两个相邻的交叉路口。下图为一张YT市的地图(n = 2),城市被划分为2
×2个区域,包括3×3个交叉路口和12条双向道路。 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期
间YT市每条道路两个方向的人流量,即在高峰期间沿着该方向通过这条道路的人数。每一个交叉路口都有不同的海
拔高度值,YT市市民认为爬坡是一件非常累的事情,每向上爬h的高度,就需要消耗h的体力。如果是下坡的话,则
不需要耗费体力。因此如果一段道路的终点海拔减去起点海拔的值为h(注意h可能是负数),那么一个人经过这段路
所消耗的体力是max{0, h}(这里max{a, b}表示取a, b两个值中的较大值)。 小Z还测量得到这个城市西北角的交
叉路口海拔为0,东南角的交叉路口海拔为1(如上图所示),但其它交叉路口的海拔高度都无法得知。小Z想知道在
最理想的情况下(即你可以任意假设其他路口的海拔高度),每天上班高峰期间所有人爬坡所消耗的总体力和的最
小值。

Input

第一行包含一个整数n,含义如上文所示。接下来4n(n + 1)行,每行包含一个非负整数分别表示每一条道路每一个
方向的人流量信息。输入顺序:n(n + 1)个数表示所有从西到东方向的人流量,然后n(n + 1)个数表示所有从北到
南方向的人流量,n(n + 1)个数表示所有从东到西方向的人流量,最后是n(n + 1)个数表示所有从南到北方向的人
流量。对于每一个方向,输入顺序按照起点由北向南,若南北方向相同时由西到东的顺序给出(参见样例输入)。

Output

仅包含一个数,表示在最理想情况下每天上班高峰期间所有人爬坡所消耗的总体力和(即总体力和的最小值),结
果四舍五入到整数。

Sample Input

1
1
2
3
4
5
6
7
8

Sample Output

3

【样例说明】
样例数据见下图。


最理想情况下所有点的海拔如上图所示。
对于100%的数据:1 ≤ n ≤ 500,0 ≤ 流量 ≤ 1,000,000且所有流量均为整数。
 
思路{
  容易发现,q起点海拔1,终点海拔0:
  只有在某一处时由1->0!!!
  那么这就是一个最小割模型,直接跑最小割的话会T,
  那么直接转化为对偶图,跑最短路即可,
  不同边边权不同没关系,只需把对偶图中边的方向换一换就可以了
}
#include<bits/stdc++.h>
#define RG register
#define il inline 
#define N 510*510
#define S 0
#define T (N-1)
#define pos(i,j) ((i-1)*n+j)
using namespace std;
struct ed{int nxt,to,c;}e[N*10];
struct Dat{
  int u,val;
  bool operator <(const Dat & a)const{
    return val>a.val;
  }
};
priority_queue<Dat>que;
int head[N],tot,d[N],n;
void link(int u,int v,int c){e[tot].nxt=head[u];e[tot].to=v;e[tot].c=c;head[u]=tot++;}
void Dijkstra(int s,int t){
  que.push((Dat){s,0});
  memset(d,127/3,sizeof(d));
  d[s]=0;
  while(!que.empty()){
    Dat tmp=que.top();que.pop();
    int u=tmp.u;
    for(int i=head[u];i!=-1;i=e[i].nxt)if(d[e[i].to]>d[u]+e[i].c){
    int v=e[i].to;
    d[v]=d[u]+e[i].c;
    que.push((Dat){v,d[v]});
      }
  }
}
 
int main(){
  memset(head,-1,sizeof(head));
  scanf("%d",&n);
  for(int i=1;i<=n+1;++i)
    for(int j=1;j<=n;++j){
      int v;scanf("%d",&v);
      if(i==1){
    link(pos(i,j),T,v);
      }
      else if(i<=n){
    link(pos(i,j),pos(i-1,j),v);
      }else {
    link(S,pos(i-1,j),v);
      }
    }
  for(int i=1;i<=n;++i)
    for(int j=1;j<=n+1;++j){
      int v;scanf("%d",&v);
      if(j==1){
    link(S,pos(i,j),v);
      }
      else if(j<=n){
    link(pos(i,j-1),pos(i,j),v);
      }else {
    link(pos(i,j-1),T,v);
      }
    }
   
  for(int i=1;i<=n+1;++i)
    for(int j=1;j<=n;++j){
      int v;scanf("%d",&v);
      if(i==1){
    link(T,pos(i,j),v);
      }
      else if(i<=n){
    link(pos(i-1,j),pos(i,j),v);
      }else {
    link(pos(i-1,j),S,v);
      }
    }
  for(int i=1;i<=n;++i)
    for(int j=1;j<=n+1;++j){
      int v;scanf("%d",&v);
      if(j==1){
    link(pos(i,j),S,v);
      }
      else if(j<=n){
    link(pos(i,j),pos(i,j-1),v);
      }else {
    link(T,pos(i,j-1),v);
      }
    }
  Dijkstra(S,T);
  cout<<d[T];
  return 0;
}

 

posted @ 2017-09-04 23:44  QYP_2002  阅读(120)  评论(0编辑  收藏  举报