[NOI2010] [洛谷P2046] 海拔 [50']

题目描述 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/output

输入格式:
第一行包含一个整数n,含义如上文所示。
接下来4n(n + 1)行,每行包含一个非负整数分别表示每一条道路每一个方向的人流量信息。输入顺序:n(n + 1)个数表示所有从西到东方向的人流量,然后n(n + 1)个数表示所有从北到南方向的人流量,n(n + 1)个数表示所有从东到西方向的人流量,最后是n(n + 1)个数表示所有从南到北方向的人流量。对于每一个方向,输入顺序按照起点由北向南,若南北方向相同时由西到东的顺序给出(参见样例输入)。
输出格式:
仅包含一个数,表示在最理想情况下每天上班高峰期间所有人爬坡所消耗的总体力和(即总体力和的最小值),结果四舍五入到整数。

输入输出样例 Sample input/output

样例测试点#1

输入样例:

1
1
2
3
4
5
6
7
8

输出样例:
3

说明 description

分析:作为一名省一的渣,做NOI的题的初衷就是能骗几分骗几分。本题经分析可得出,虽然节点的海拔题目说可能为实数,但只能是0或1。在流量最少的地方使海拔上升到1,才能在流量最大的地方少花体力。也就是说选取一些边,这些边将源点和汇点分成两部分。由此很明显了本题是最小割。至于最小割怎么求那就出现了差别。对于AC程序,是利用了“平面图最小割=最短路”即把每一个方格看做一个点,方格之间连两条有向边,有向边的权值为边所割的边的权值。跑SPFA可得80分,Heap+Dijkstra可成功AC。若利用“最小割=最大流”定理,合理建图+数组模拟链表,dinic可得50分。

至于建图,若求最大流,则可从2开始存边,紧接着存反向边。这样在求最大流找反向边的过程中可简单get。比如2存正向边,3存反向边。2^1=3,3^1=2。可大大提高程序效率。

50分dinic代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int head[500001],next[500001],list[500001],key[500001],dis[250001],sq[500001],n,x,sum,delta,ans,t;
void insert(int i,int j,int x)
{
     sum+=2;
     next[sum]=head[i];
     head[i]=sum;
     list[sum]=j;
     key[sum]=x;
}
bool BFS()
{
     memset(dis,0xff,sizeof(dis));
     dis[1]=0;
     int l=0,r=1,x,y; sq[1]=1;
     while (l<r)
     {
           l++;
           y=sq[l];
           x=head[y];
           while (x!=0)
           {
                 if (dis[list[x]]<0&&key[x]>0)
                 {
                                    dis[list[x]]=dis[y]+1;
                                    r++;
                                    sq[r]=list[x];
                 }
                 x=next[x];
           }
     }
     if (dis[t]>0) return true; else return false;
}
int find(int x,int low)
{
    if (x==t) return low;
    int a=0,y=head[x];
    while (y!=0)
    {
          if (key[y]>0&&dis[list[y]]==dis[x]+1&&(a=find(list[y],min(low,key[y]))))
          {
                                                                       key[y]-=a;
                                                                       key[y^1]+=a;
                                                                       return a;
          }
          y=next[y];
    }
    return 0;
}
int main()
{
    scanf("%d",&n);
    sum=0;
    for (int i=0;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
            scanf("%d",&x);
            insert((n+1)*i+j,(n+1)*i+j+1,x);
        }
    for (int i=0;i<n;i++)
        for (int j=1;j<=n+1;j++)
        {
            scanf("%d",&x);
            insert(i*(n+1)+j,(i+1)*(n+1)+j,x);
        }
    sum=1;
    for (int i=0;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
            scanf("%d",&x);
            insert((n+1)*i+j+1,(n+1)*i+j,x);
        }
    for (int i=0;i<n;i++)
        for (int j=1;j<=n+1;j++)
        {
            scanf("%d",&x);
            insert((i+1)*(n+1)+j,i*(n+1)+j,x);
        }
    t=(n+1)*(n+1);
    ans=0;
    while (BFS())
          while (delta=find(1,0x7fffffff)) ans+=delta;
    printf("%d",ans);
    return 0;
}  

测试点 #1通过该测试点。 得分10,耗时0ms,内存3088kB。
测试点 #2通过该测试点。 得分10,耗时0ms,内存3080kB。
测试点 #3通过该测试点。 得分10,耗时0ms,内存3084kB。
测试点 #4通过该测试点。 得分10,耗时0ms,内存3096kB。
测试点 #5通过该测试点。 得分10,耗时15ms,内存3092kB。
测试点 #6超过时间限制。 得分0,内存3108kB。
测试点 #7超过时间限制。 得分0,内存3117kB。
测试点 #8超过时间限制。 得分0,内存3137kB。
测试点 #9超过时间限制。 得分0,内存11042kB。
测试点 #10超过时间限制。 得分0,内存11046kB。

[NOI2010] [洛谷P2046] 海拔 [50']

时间: 2024-12-27 15:53:12

[NOI2010] [洛谷P2046] 海拔 [50']的相关文章

洛谷P1081 开车旅行

P1081 开车旅行 152通过 524提交 题目提供者洛谷OnlineJudge 标签倍增NOIp提高组2012 难度省选/NOI- 提交该题 讨论 题解 记录 最新讨论 我前排提醒一下 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi−

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不

洛谷P1160 队列安排 链表

洛谷P1160 队列安排   链表 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std

[题解]洛谷比赛『期末考后的休闲比赛2』

[前言] 这场比赛已经结束了有几天,但我各种忙,虽然AK但还是没来得及写题解.(我才不会告诉你我跑去学数据结构了) T1 区间方差 (就不贴题好了) 首先可以推公式(我们可以知道,线段树然而并不能通过初中学过的方差公式在log(L)内求出方差): (s2表示方差,L表示区间长度,xi表示区间的每一项,最后一个x上画了一根线表示这些数据的平均数) 用二项式定理完全平方公式可得: 再次展开: 另外,再代入以下这个 得到了: 然后继续吧.. 然后duang地一声合并同类项,于是我们得到了: 然后可以高

洛谷P1471 方差

蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差. ——by 洛谷; http://www.luogu.org/problem/show?pid=1471 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

升序堆和降序堆(优先队列) 洛谷1801

1 // 洛谷1801 2 // 一个升序堆,一个降序堆 3 // 降序堆维护序列的前i个最小值 4 // 插如元素的时候,如果x小于降序堆最大值,则替换,并将最大值插入升序堆:否则,直接插入升序堆 5 // 每次输出升序堆的最小值即可 6 7 8 #include <bits/stdc++.h> 9 using namespace std; 10 #define LL long long 11 typedef pair<int,int> pii; 12 const int inf

洛谷 P1219 八皇后 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1219 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下: 行号 1 2 3 4 5 6 列号 2 4 6 1 3 5 这只是跳

洛谷P1083 借教室 二分 + 差分

洛谷P1083 借教室 二分 + 差分(或说前缀和,其实前缀和更准确一点) 首先二分答案,即取 mid 个人,且他们不会冲突 然后O(n) 判断是否冲突 如何判断呢,首先我们发现 一个人的操作相当于是将 一些连续的山削去了一个高度 然后我们可以记录这座山被消了多少高度,但这样一次就要 O(N) 总共(n^2) 但是我们发现高度差只有两个地方变了,一个是起始,一个是终止 t[ i ] 表示 h[ i ] - h[ i-1 ] 改变过后 于是 t[ s ]-=d,t[ t+1 ]+=d ; 然后这样

洛谷P3385 【模板】负环 DFS-SPFA 判负环 图论

洛谷P3385 [模板]负环 图论 今天get了 一个 DFS-SPFA 判负环的方法 一般的 BFS-SPFA 判负环 一般就是 不停地做,如果某点第 n+1次加入队列中,那么说明这个图存在负环然而我并不会证明,期望复杂度是 O(kM) k 大约是在 2 左右 但是其实对于一些极限数据,最坏可以把他卡到 O( NM) 额,这就直接炸飞了是不是,而且据说,一些数据比较强的题目,总会想到卡一卡SPFA的, 然后我们换一种思路 因为题目中一定存在一种 负环对吧,所以说假如你某段路径权值和为自然数的时