P1514 引水入城

题目描述

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

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

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

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

思路:

1.通过dfs找出在第一行每一个城市可以输送到最后一行的那些城市。

   但是我们发现,这几个被输送的城市总是相连的,于是,我们只需要记录最左和最右的能输送到的城市。

2于是转换成了一个区间覆盖问题,求最少用几条线段能覆盖最后一行。

   可以用dp来解,f【i】表示前i个点最少需要多少条线段:

   f[i]=min(f[i],f[l[j]-1]+1)前提是:(i>=l[j]&&i<=r[j])

   l【j】表示第一行第j的城市所能覆盖的最后一行城市的左端点;

   r【j】表示第一行第j的城市所能覆盖的最后一行城市的右端点;

代码解释:

​
​#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int map[555][555],n,m,r[555],l[555],f[555];
bool v[555][555],ans[555];
void dfs(int x,int y,int begin)
{
	v[x][y]=1;
	if(x==n)//如果到了最后一行
	{
		ans[y]=1;//最后一行的第y个城市能建蓄水站
		l[begin]=min(l[begin],y);
		r[begin]=max(r[begin],y);
	}
    //这里一定要注意!搜到最后一行还要往下搜(我当时加了一个else就错了好多次QAQ)
    if(x!=n&&!v[x+1][y]&&map[x+1][y]<map[x][y])dfs(x+1,y,begin);
    if(x!=1&&!v[x-1][y]&&map[x-1][y]<map[x][y])dfs(x-1,y,begin);
    if(y!=m&&!v[x][y+1]&&map[x][y+1]<map[x][y])dfs(x,y+1,begin);
    if(y!=1&&!v[x][y-1]&&map[x][y-1]<map[x][y])dfs(x,y-1,begin);
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	l[i]=f[i]=99999;
	f[0]=0;
	for(int i=1;i<=n;i++)
	for(int l=1;l<=m;l++)
	cin>>map[i][l];
	for(int i=1;i<=m;i++)
	{
	if((map[1][i]>=map[1][i-1])&&(map[1][i]>=map[1][i+1]))//剪枝:只有这个点比左右都高才去判定,否则必有另外一点比它的覆盖更广。
	dfs(1,i,i);
	memset(v,0,sizeof(v));//每次搜索后都要归零.
	}
	int anss=0;
	for(int i=1;i<=m;i++)
	if(!ans[i])anss++;
	if(!anss)
	{
		cout<<1<<endl;
	    for(int i=1;i<=m;i++)//用动态规划来求出能够满足时最少需要的蓄水厂的个数
        for(int j=1;j<=m;j++)
        if(i>=l[j]&&i<=r[j])
        f[i]=min(f[i],f[l[j]-1]+1);
        cout<<f[m];
	}
    else
    {
    cout<<0<<endl;
    cout<<anss;	
	}
	return 0;
}

​

​
posted @ 2018-07-19 20:25  qkm  阅读(98)  评论(0编辑  收藏  举报