[FT][8]NOIP 2010 引水入城

题目描述

在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。

这里写图片描述

为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。

因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

输入输出格式
输入格式:

输入文件的每行中两个数之间用一个空格隔开。输入的第一行是两个正整数N 和M,表示矩形的规模。接下来N 行,每行M 个正整数,依次代表每座城市的海拔高度。

输出格式:

输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。

输入输出样例

输入样例#1:
【输入样例1】
2 5
9 1 5 4 3
8 7 6 1 2

【输入样例2】
3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2

输出样例#1:
【输出样例1】
1
1

【输出样例2】
1
3

说明

【样例1 说明】

只需要在海拔为9 的那座城市中建造蓄水厂,即可满足要求。

【样例2 说明】
这里写图片描述

上图中,在3 个粗线框出的城市中建造蓄水厂,可以满足要求。以这3 个蓄水厂为源头

在干旱区中建造的输水站分别用3 种颜色标出。当然,建造方法可能不唯一。

【数据范围】

这里写图片描述


【分析】
怎么讲呢…只能怪自己学艺不精,题都没读全就开始乱写。一开始以为所有地方都要被灌到才输出1…拿了30…最后乱搞搞终于过了…

思路:
枚举第一行每个点进行bfs,算出每个点能扩展到最后一行的左端点与右端点。这里有一个剪枝:如果该点的海拔>=左右两点的海拔那么可选,其它情况选了也是重复搜索。
至于左端点与右端点…首先我们要证明如果输出的是1的话,那么扩展到最后一行一定是连续的一段区间。
这玩意证明就很神奇了…不过也不是很难证明,我自己想了想推出来了…用的是反证法。
对于最后一行的一个点i,如果它的左边和右边都到达了,而它却无法到达,那么海拔比它高的只有它的上面了。设它上面的点为j,如果我们想到达j,那么我们仍然只能从j的上面到达,因为如果是由j的左右到达的话,那么i点的左右必定也能到达。一次类推,发现i所在的一列就变成了一个“屏障”,左边的点流不到右边,右边流不到左边,只有这一列能流向两边…显然与“区间不连续”相违背…
所以把点变成了许多线段,转换成了区间覆盖问题,贪心法求解。


【代码】

//NOIP 2010 引水入城
#include
#include
#include
#include
#include
#include
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=1e6;
int n,m,t,cnt,num;
int map[505][505],get[505];
int u[5]={0,-1,1,0,0},v[5]={0,0,0,-1,1};
bool vis[505][505],oth[505][505];
struct inter {int l,r;} p[505];
inline bool comp(const inter &x,const inter &y) {return x.linline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void dfs(int x,int y)
{
    int i,j;
    vis[x][y]=oth[x][y]=1;
    if(x==n) p[t].l=min(p[t].l,y),p[t].r=max(p[t].r,y);
    fo(i,1,4)
    {
        int xx=x+u[i],yy=y+v[i];
        if(xx>=1 && xx<=n && yy>=1 && yy<=m && map[xx][yy]<map[x][y] && !oth[xx][yy])
          dfs(xx,yy);
    }
}
inline void dynamic(int x)
{
    int i,j,L,R,ans=1;
    sort(p+1,p+x+1,comp);
    fo(i,1,x) if(p[i].l!=0) break;
    L=p[i].l,R=p[i].r;i++;
    fo(i,i,x) if(p[i].l==1) R=max(R,p[i].r);else break;
    while(i<=x)
    {
        ans++;
        int tmp=R;
        fo(i,i,x)
        {
            if(p[i].l<=tmp+1) R=max(R,p[i].r);
            else break;
        }
        if(R==tmp) ans--;
        if(R==m) break;
    }
    printf("1\n%d\n",ans);
    exit(0);
}
int main()
{
    int i,j,flag=0;
    n=read(),m=read();
    fo(i,1,n)
      fo(j,1,m)
        map[i][j]=read();
    fo(j,1,m)
      if(map[1][j]>=map[1][j-1] && map[1][j]>=map[1][j+1])
        get[++cnt]=j;
    fo(t,1,cnt)
    {
        p[t].l=505;M(oth);
        dfs(1,get[t]);
        num=0;
        fo(i,1,m)
          if(vis[n][i]) num++;
        if(num==m) dynamic(i);
    }
    num=0;
    fo(i,1,m) if(!vis[n][i]) num++;
    printf("0\n%d\n",num);
    return 0;
}

你可能感兴趣的:(贪心,宽搜)