图论(对偶图):COGS 470. [NOI2010]海拔

时间:2021-05-23 19:52:09

470. [NOI2010]海拔

★★★☆   输入文件:altitude.in   输出文件:altitude.out   简单对比
时间限制:2 s  
内存限制:512 MB

海拔

【问题描述】

  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想知道在最理想的情况下(即你可以任意假设其他路口的海拔高度),每天上班高峰期间所有人爬坡消耗的总体力和的最小值。

【输入格式】

  第一行包含一个整数n,含义如上文所示。

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

【输出格式】

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

【样例输入】

1

1

2

3

4

5

6

7

8

【样例输出】

3

【样例说明】

  样例数据见下图。

  最理想情况下所有点的海拔如上图所示。

【数据规模】

  对于20%的数据:n ≤ 3;

  对于50%的数据:n ≤ 15;

  对于80%的数据:n ≤ 40;

  对于100%的数据:1 ≤ n ≤ 500,0 ≤ 流量 ≤ 1,000,000且所有流量均为整数。

【提示】

  海拔高度不一定是整数。

【运行时限】

  2秒。

【运行空限】

  512M。

  
  这道题转换成对偶图,跑迪杰斯特拉+heap(不知为啥,spfa+slf优化不能过)。

  

 #include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=;
const int maxm=;
int cnt,fir[maxn],nxt[maxm],to[maxm],val[maxm];
void addedge(int a,int b,int d){
nxt[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;val[cnt]=d;
}
int S,T,n;
int dis[maxn];
struct Data{
int dis,node;
};
struct Node{
Data heap[maxn];
int cnt;
void Insert(Data x){
int p=++cnt;
while(p!=){
if(heap[p>>].dis<=x.dis)break;
heap[p]=heap[p>>];
p>>=;
}
heap[p]=x;
}
void Delete(){
int p=,a,b;
Data x=heap[cnt--];
while(p*<=cnt){
a=p<<;b=a|;
if(b>cnt||heap[b].dis>heap[a].dis)b=a;
if(heap[b].dis>=x.dis)break;
heap[p]=heap[b];
p=b;
}
heap[p]=x;
}
}q; int Solve(){
memset(dis,,sizeof(dis));
dis[S]=;q.Insert((Data){dis[S],S});
while(true){
int node=q.heap[].node;q.Delete();
if(node==T)break;
for(int i=fir[node];i;i=nxt[i])
if(dis[to[i]]>dis[node]+val[i]){
dis[to[i]]=dis[node]+val[i];
q.Insert((Data){dis[to[i]],to[i]});
}
}
return dis[T];
} int main(){
freopen("altitude.in","r",stdin);
freopen("altitude.out","w",stdout);
scanf("%d",&n);
S=;T=n*n+;
int a,b,d;
for(int i=;i<=n+;i++)
for(int j=;j<=n;j++){
scanf("%d",&d);
a=i==n+?S:(i-)*n+j;
b=i==?T:(i-)*n+j;
addedge(a,b,d);
} for(int i=;i<=n;i++)
for(int j=;j<=n+;j++){
scanf("%d",&d);
a=j==?S:(i-)*n+j-;
b=j==n+?T:(i-)*n+j;
addedge(a,b,d);
} for(int i=;i<=n+;i++)
for(int j=;j<=n;j++){
scanf("%d",&d);
a=i==n+?S:(i-)*n+j;
b=i==?T:(i-)*n+j;
addedge(b,a,d);
} for(int i=;i<=n;i++)
for(int j=;j<=n+;j++){
scanf("%d",&d);
a=j==?S:(i-)*n+j-;
b=j==n+?T:(i-)*n+j;
addedge(b,a,d);
} printf("%d\n",Solve());
return ;
}