bzoj 2007:[noi2010]海拔

19 篇文章 0 订阅
6 篇文章 0 订阅
题目描述 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 Description

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

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

输出描述 Output Description

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

样例输入 Sample Input

1

1

2

3

4

5

6

7

8

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

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

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

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

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

海拔高度不一定是整数。

spfa竟然TLE了!

现学dijkstra= =

还是平面图最小割转化为对偶图最短路做。。

直接上代码好了= =建图详见main()


#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
int head[1000001];
struct map
{
	 int f;
	 int s,t;
     int next;
}a[4000001];
int edge;
inline void add(int s,int t,int f)
{
     a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
     a[edge].f=f;
}
/*int dis[250005];
bool v[250005];
queue <int>Q;
inline void spfa()
{
     memset(dis,127/3,sizeof(dis));
     memset(v,false,sizeof(v));
     while(!Q.empty())
          Q.pop();
     Q.push(0);
     dis[0]=0;
     v[0]=true;
     while(!Q.empty())
     {
          int d=Q.front();
          Q.pop();
          v[d]=false;
          int i;
          for(i=head[d];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               if(dis[d]+a[i].f<dis[t])
               {
                    dis[t]=dis[d]+a[i].f;
                    if(!v[t])
                    {
                         v[t]=true;
                         Q.push(t);
                    }
               }
          }
     }
}*/
struct save
{
     int x,d;
     bool operator< (save xx) const
     {
          return d>xx.d;
     }
};
priority_queue <save>Q;
int dis[250005];
bool v[250005];
inline void dijstra()
{
     memset(dis,127/3,sizeof(dis));
     memset(v,false,sizeof(v));
     while(!Q.empty())
          Q.pop();
     save d;
     d.x=0;
     d.d=0;
     Q.push(d);
     dis[0]=0;
     while(!Q.empty())
     {
          d=Q.top();
          Q.pop();
          while(v[d.x]&&!Q.empty())
          {
               d=Q.top();
               Q.pop();
          }
          if(v[d.x]&&Q.empty())
               break;
          v[d.x]=true;
          int i;
          for(i=head[d.x];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               if(dis[d.x]+a[i].f<dis[t])
               {
                    dis[t]=dis[d.x]+a[i].f;
                    if(!v[t])
                    {
                         save tt;
                         tt.x=t;
                         tt.d=dis[t];
                         Q.push(tt);
                    }
               }
          }
     }
}
int main()
{
     int n;
     scanf("%d",&n);
     int i,j,x;
     for(i=1;i<=n+1;i++)
     {
          for(j=1;j<=n;j++)
          {
               scanf("%d",&x);
               if(i==1)
               {
                    edge++;
                    add(j,n*n+1,x);
               }
               else if(i==n+1)
               {
                    edge++;
                    add(0,(i-2)*n+j,x);
               }
               else
               {
                    edge++;
                    add((i-1)*n+j,(i-2)*n+j,x);
               }
          }
     }
     for(i=1;i<=n;i++)
     {
          for(j=1;j<=n+1;j++)
          {
               scanf("%d",&x);
               if(j==1)
               {
                    edge++;
                    add(0,(i-1)*n+1,x);
               }
               else if(j==n+1)
               {
                    edge++;
                    add((i-1)*n+j-1,n*n+1,x);
               }
               else
               {
                    edge++;
                    add((i-1)*n+j-1,(i-1)*n+j,x);
               }
          }
     }
     for(i=1;i<=n+1;i++)
     {
          for(j=1;j<=n;j++)
          {
               scanf("%d",&x);
               if(i==1)
               {
                    edge++;
                    add(n*n+1,j,x);
               }
               else if(i==n+1)
               {
                    edge++;
                    add((i-2)*n+j,0,x);
               }
               else
               {
                    edge++;
                    add((i-2)*n+j,(i-1)*n+j,x);
               }
          }
     }
     for(i=1;i<=n;i++)
     {
          for(j=1;j<=n+1;j++)
          {
               scanf("%d",&x);
               if(j==1)
               {
                    edge++;
                    add((i-1)*n+1,0,x);
			   }
               else if(j==n+1)
               {
                    edge++;
                    add(n*n+1,(i-1)*n+j-1,x);
               }
               else
               {
                    edge++;
                    add((i-1)*n+j,(i-1)*n+j-1,x);
               }
          }
     }
     dijstra();
     //spfa();
     printf("%d\n",dis[n*n+1]);
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值