P1514 引水入城 DFS

  

题目描述

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

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:  复制
2 5
9 1 5 4 3
8 7 6 1 2
输出样例#1:  复制
1
1
输入样例#2:  复制
3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2
输出样例#2:  复制
1
3


非常好的一道搜索题目
贪心+DFS即可解决 这题DFS很简单 主要是后期处理

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 0x3f3f3f3f
#define N 5005
int n,m;
int mp[N][N];
int vis[N][N];
int vis2[N];
int ri[N];
vector<int>node[N];//该城市所到达的点
vector<int>in[N];//到达该点的城市
bool inmap(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=m;
}
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
void dfs(int x,int y,int flag)
{
    if(x==n)
    {
        node[flag].push_back(y);
        ri[flag]=max(ri[flag],y);
        in[y].push_back(flag);
        vis2[y]=1;
    }
    rep(i,0,3)
    {
        int a=x+dx[i];
        int b=y+dy[i];
        if(!inmap(a,b))continue;
        if(vis[a][b]==flag)continue;
        if(mp[a][b]>=mp[x][y])continue;
        vis[a][b]=flag;
        dfs(a,b,flag);
    }
}
struct aaa
{
    int id,h;
}s[N];
bool cmp(aaa a,aaa b)
{
    return a.h>b.h;
}
int main()
{
    RII(n,m);
    rep(i,1,n)
    rep(j,1,m)
    {
        RI(mp[i][j]);
        if(i==1)
        s[j].id=j,s[j].h=mp[i][j];
    }
    sort(s+1,s+1+m,cmp);//贪心优化 高的先来  剪了30ms。。。

    rep(i,1,m)
    if(!vis[1][ s[i].id ])
    dfs(1,s[i].id,s[i].id);
    
    int ok=1;
    int cnt=0;
    rep(i,1,m)
    if(!vis2[i])ok=0,cnt++;
    if(!ok)printf("%d\n%d",0,cnt);
    else
    {
        printf("1\n");
        
        int sum=0;
        int i=1;
        while(i<=m)
        {
            int maxx=0;
            rep(j,0,in[i].size()-1)
                maxx=max(maxx, ri[ in[i][j] ] );
            
            sum++;
            i=maxx+1;
        }
        cout<<sum;
    }
    return 0;
}
View Code
大佬的做法   速度比我的快一倍QAQ

递归求左界和右界非常巧妙
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <stack>
using namespace std;
#define maxn 510
#define nx x+xx[i]
#define ny y+yy[i]
int l[maxn][maxn],r[maxn][maxn];
int high[maxn][maxn];
int n,m;
bool vis[maxn][maxn];
int xx[4]={-1,0,1,0};
int yy[4]={0,1,0,-1};
int qx[maxn*maxn],qy[maxn*maxn];

inline void dfs(int x,int y)
{
    vis[x][y]=true;
    for (int i=0;i<4;i++){
        if (nx<1 || nx>n || ny<1 || ny>m) continue;
        if (high[nx][ny]>=high[x][y]) continue;
        if (!vis[nx][ny])dfs(nx,ny);
        l[x][y]=min(l[x][y],l[nx][ny]);
        r[x][y]=max(r[x][y],r[nx][ny]);
    }
}

inline int read()
{
    int ret=0;
    char c=getchar();
    while (c<'0' || c>'9') c=getchar();
    while (c>='0' && c<='9'){
        ret=ret*10+c-'0';
        c=getchar();
    }
    return ret;
}

int main()
{
    n=read();
    m=read();
    memset(vis,false,sizeof(vis));
    memset(l,0x3f,sizeof(l));
    memset(r,0,sizeof(r));
    for (int i=1;i<=m;i++)
        l[n][i]=r[n][i]=i;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)    
            high[i][j]=read();
    for (int i=1;i<=m;i++)
        if (!vis[1][i]) dfs(1,i);
    bool flag=false;
    int cnt=0;
    for (int i=1;i<=m;i++)    
        if (!vis[n][i]){
            flag=true;
            cnt++;
        }
    if (flag){
        puts("0");
        printf("%d",cnt);
        return 0;
    }
    int left=1;
    while (left<=m){
        int maxr=0;
        for (int i=1;i<=m;i++)
            if (l[1][i]<=left)
                maxr=max(maxr,r[1][i]);
        cnt++;
        left=maxr+1;
    }
    puts("1");
    printf("%d",cnt);
}
View Code






猜你喜欢

转载自www.cnblogs.com/bxd123/p/10729447.html