NOI2010 海拔
2015-09-29 17:39
204 查看
问题描述
小 Z 作为该市的市长,他根据统计信息得到了每天上班高峰期间 YT 市每条道路两个方向的人流量,即在高峰期间沿 着该方向通过这条道路的人数。每一个交叉路口都有不同的海拔高度值,YT 市市民认为爬坡是一件非常累的事情,每向上爬 h 的高度,就需要消耗 h的体力。如果 是下坡的话,则不需要耗费体力。因此如果一段道路的终点海拔减去起点海拔的值为 h(注意 h 可能是负数),那么一个人经过这段路所消耗的体力是 max{0, h}(这里max{a, b}表示取 a, b 两个值中的较大值)。小 Z 还测量得到这个城市西北角的交叉路口海拔为 0,东南角的交叉路口海拔为1(如上图所示),但其它交叉路口的海拔高度都无法得知。小 Z 想知道在最理想的情况下(即你可以任意假设其他路口的海拔高度),每天上班高峰期间所有人爬坡消耗的总体力和的最小值。
输入格式
输入文件 altitude.inaltitude.in 第一行包含一个整数 n,含义如上文所示。接下来 4n(n + 1)行,每行包含一个非负整数分别表示每一条道路每一个方向的人流量信息。输入顺序:n(n + 1)个数表示所有从西到东方向的人流量,然后 n(n + 1)个数表示所有从北到南方向的人流量,n(n + 1)个数表示所有从东到西方向的人流量,最后是 n(n + 1)个数表示所有从南到北方向的人流量。对于每一个方向,输入顺序按照起点由北向南,若南北方向相同时由西到东的顺序给出(参见样例输入)。输出格式
输出文件 altitude.outaltitude.out 仅包含一个数,表示在最理想情况下每天上班高峰期间所有人爬坡所消耗的总体力和(即总体力和的最小值),结果四舍五入到整数。样例输入
11
2
3
4
5
6
7
8
样例输出
3找出图中海拔最高的点,如果它不是起止点,那么这条路径必定是先上坡再下坡,这样就会浪费了体力,我们可以将最高点下调至他两边较高的点。那么你可以发现,最高点一定是终点,而最低点就是起始点。
还有一个问题是小数,其实小数的问题很好解决,可以把小数向上或向下调整到1或0使得代价不增。
那么当你完全想到上面两点时,你会发现为0的点和为1的点构成两个相通的集合时,体力消耗最少值就是就是连接这两个集合的所有边权之和。
那么就可以想到
最小割
但是点数是n2n^2的。不能用最大流。#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define maxn 505 #define maxm maxn*maxn*4 using namespace std; int head[maxn*maxn],next[maxm],t[maxm],v[maxm],sum; int n; int dis[maxn*maxn],d[maxn*maxn*300]; bool bz[maxn*maxn]; int poi(int x,int y){return (x-1)*n+y;} void insert(int x,int y,int z){ t[++sum]=y; v[sum]=z; next[sum]=head[x]; head[x]=sum; } void spfa(){ int l=maxn*maxn*100,r=l; d[l]=0; memset(dis,63,sizeof(dis)); dis[0]=0; bz[0]=1; while (l<=r){ int now=d[l]; bz[now]=0; for(int tmp=head[now];tmp;tmp=next[tmp]){ if (dis[t[tmp]]>dis[now]+v[tmp]){ dis[t[tmp]]=dis[now]+v[tmp]; if (!bz[t[tmp]]){ bz[t[tmp]]=1; d[++r]=t[tmp]; if (dis[t[tmp]]<dis[d[l+1]]){ d[l--]=t[tmp]; r--; } } } } l++; } } int main(){ scanf("%d",&n); int x; fo(i,1,n) { scanf("%d",&x); insert(0,poi(1,i),x); } fo(i,1,n-1) fo(j,1,n) { scanf("%d",&x); insert(poi(i,j),poi(i+1,j),x); } fo(i,1,n){ scanf("%d",&x); insert(poi(n,i),poi(n+1,1),x); } fo(i,1,n){ scanf("%d",&x); insert(poi(i,1),poi(n+1,1),x); fo(j,2,n){ scanf("%d",&x); insert(poi(i,j),poi(i,j-1),x); } scanf("%d",&x); insert(0,poi(i,n),x); } fo(i,1,n) scanf("%d",&x); fo(i,1,n-1) fo(j,1,n){ scanf("%d",&x); insert(poi(i+1,j),poi(i,j),x); } fo(i,1,n) scanf("%d",&x); fo(i,1,n){ scanf("%d",&x); fo(j,1,n-1) { scanf("%d",&x); insert(poi(i,j),poi(i,j+1),x); } scanf("%d",&x); } spfa(); printf("%d\n",dis[poi(n+1,1)]); return 0; }
相关文章推荐
- 分解质因数
- js跳转页面并传值以及localStorage的用法
- Java基础---java虚拟机内存结构
- 归并排序
- java 接口、抽象类、具体类、内部类、匿名内部类的区别及它们之间的关系
- HTTP协议详解(版本二)
- windbg ida需要symbols
- Eclipse+APKTool动态调试APK
- c 开源代码
- poj 2689
- rz和sz 和他们的参数们
- effective c++ 令operator=返回一个reference to *this
- ICV hash校验值不符的问题
- 工厂模式
- SpringMVC
- poj 1848 树形dp(添加最少的边每点都恰在一个圈中)
- ubuntu下grub启动硬盘iso安装ubuntu
- 再回首【Android 自定义View (二) 进阶】
- Asp.Net alert 方法
- Oracle直接路径加载--append的深度解析