题目描述 Description
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政 区划十分特殊,刚好构成一个N行M列的矩形,如上图所示,其中每个格子都代表一座城 市,每座城市都有一个海拔高度。 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施 有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的 蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通 过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是 存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。 由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利 设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干 旱区中不可能建有水利设施的城市数目。
输入描述 Input Description
输入的每行中两个数之间用一个空格隔开。 输入的第一行是两个正整数N和M,表示矩形的规模。 接下来N行,每行M个正整数,依次代表每座城市的海拔高度。
输出描述 Output Description
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少 建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有 几座干旱区中的城市不可能建有水利设施。
样例输入 Sample Input
2 5
9 1 5 4 3
8 7 6 1 2
样例输出 Sample Output
1
1
题目要求的结果共有两种情况,一种是在底部不能够全部连通的情况输出不能连通的城市数,第二种是在连通的情况下用在顶部用最少的蓄水站将底部灌满
对于不同的情况,则需要进行一次灌水来进行判断
那么:何为灌水呢
个人的理解是这样,对于图上的处理,就像实际中一样,将水流从高度高的位置向四周较低的位置蔓延覆盖,然后将其覆盖到底位置染色
程序实现就是从当前点开始,向四周遍历,将高度比当前点低的点入队,重复操作处理整个图
对于这道题,从顶部向下灌水遍历,将底部染色(标个号)
如果全部遍历一遍后底部仍有未被染色的,那么这种情况便是不连通的
如果连通呢
对于顶部每一个可建蓄水站的城市,如果在这座城市建蓄水站的话,则将在底部沙漠中获得一段可覆盖的连续区间:一个可被覆盖的底部沙漠城市只可被其左边,右边,上边的城市灌水(x,y+1||x,y-1||x-1,y)如果左右两边的城市被淹没的话,则该城市必被淹没,如果不能,也不会存在另外的点能够经过其周围的三个点淹没这座城市,所以淹没的城市必是一段连续的区间
证明这一点之后,每座顶部的蓄水站都会有一段覆盖底部城市的区间
由于底部一定会被这些区间完全覆盖,于是问题就转化成了尽量用少的已知区间覆盖整个底部区间,答案就是所使用的区间个数
于是问题的难点就转化成了线段覆盖!
这个地方比较正常的做法是dp== 但是仔细一想贪心是完全成立的:
将所有的线段(区间)全部按照右端点从大往小,左端点从小往大双关键字排序。
第一条线段必定选(右端点最靠右的线段中左端点最靠左),那么从此之后的线段选择的条件为:右端点必须在已覆盖的区间内,左端点超出已覆盖区间的长度最长
处理完所有的线段后,既是用最少的线段完成了整个区间的覆盖
最后输出已选线段个数就完成了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=233333;
int map[510][510];
bool use[maxn];
struct doubi{
int l,r;
}num[maxn];
bool cmp(doubi a,doubi b){
if(a.l!=b.l) return a.l<b.l;
return a.r>b.r;
}
int ans;
int n,m;
int x_x[5]={0,0,0,1,-1};
int y_y[5]={0,1,-1,0,0};
struct faq{
int x,y;
};
queue<faq> q;
bool can(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m){
return true;
}
return false;
}
bool fa[800][800];
void bbfs(int u,int j)
{
faq s;
s.x=u,s.y=j;
fa[u][j]=1;
q.push(s);
while(!q.empty())
{
faq u=q.front();
q.pop();
int x=u.x,y=u.y;
if(x==n){
use[y]=1;
}
for(int i=1;i<=4;i++){
int X=x+x_x[i];
int Y=y+y_y[i];
if(can(X,Y)&&!fa[X][Y]&&map[X][Y]<map[x][y]){
faq nxt;
nxt.x=X,nxt.y=Y;
fa[X][Y]=1;
q.push(nxt);
}
}
}
}
bool check()
{
for(int i=1;i<=m;i++){
bbfs(1,i);
}
for(int i=1;i<=m;i++){
if(!use[i]) return false;
}
return true;
}
void bfs(int u)
{
memset(use,0,sizeof(use));
faq s;
s.x=1,s.y=u;
q.push(s);
while(!q.empty())
{
faq u=q.front();
q.pop();
int x=u.x,y=u.y;
if(x==n){
use[y]=1;
}
for(int i=1;i<=4;i++){
int X=x+x_x[i];
int Y=y+y_y[i];
if(can(X,Y)&&map[X][Y]<map[x][y]){
faq nxt;
nxt.x=X,nxt.y=Y;
q.push(nxt);
}
}
}
}
bool vis[maxn];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&map[i][j]);
}
}
if(!check()){
puts("0");
int cnt=0;
for(int i=1;i<=m;i++){
if(!use[i]){
cnt++;
}
}
cout<<cnt<<endl;
return 0;
}
else
{
puts("1");
for(int i=1;i<=m;i++){
bfs(i);
int s=0,t=0;
for(int j=1;j<=m;j++){
if(use[j]){
s=j;
for(t=s;t<=m+1;t++){
if(!use[t]){
t--;
goto fuckcy;
}
}
}
}
fuckcy:;
num[i].l=s,num[i].r=t;
}
sort(num+1,num+m+1,cmp);
int now=0,to=0,tot=0;
for(int i=1;i<=m;i++)
{
if(now+1>=num[i].l) to=max(to,num[i].r);
else now=to,to=max(to,num[i].r),tot++;
}
if(now!=m)tot++;
cout<<tot<<endl;
}
}