引水入城(洛谷_1514)

这题好像是200几年的题,

主要就是贪心加bfs。

求出每一个点流出的水,能遍布哪一些。

有一个优化,就是,当前点要比左右两边都高,才遍历。

而且遍历完之后,最后一行一定是连续的区间,否则就是有位置不能被覆盖。

然后这题就转换成了区间覆盖问题,贪心求解。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
inline int read(){
    int t=1,num=0;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();}
    return num*t;
}
const int N=510;
const int xt[4]={-1,0,0,1};
const int yt[4]={0,-1,1,0};
int n,m,a[N][N],d[N][N],cov[N],cnt=0;
struct note{int x,y;};
struct edge{int l,r;}b[N];
void bfs(int s){
    memset(d,0,sizeof(d));
    queue<note> q;
    q.push((note){1,s});d[1][s]=1;
    while(!q.empty()){
        note t=q.front();q.pop();
        for(int j=0;j<4;j++){
            int x=t.x+xt[j],y=t.y+yt[j];
            if(x<1||y<1||x>n||y>m)continue;
            if(d[x][y]==0&&a[x][y]<a[t.x][t.y]){
                d[x][y]=1;q.push((note){x,y});
            }
        }
    }
    int f,t;f=t=-1;
    for(int i=1;i<=m;i++){
        if(f==-1&&d[n][i]==1)f=i;
        if(d[n][i]==1&&d[n][i+1]==0)t=i;
        cov[i]|=d[n][i];
    }
    if(f!=-1)b[++cnt].l=f,b[cnt].r=t;
}
bool cmp(edge i,edge j){return i.l<j.l;}
void tanxin(){
    int ans=1,s=1,nxt=1;
    sort(b+1,b+1+cnt,cmp);
    for(int i=1;i<=cnt;i++){
        if(b[i].l<=s)nxt=max(nxt,b[i].r);    
        else{
            ans++;s=nxt+1;
            nxt=max(nxt,b[i].r);
        }
        if(nxt>=m)break;
    }
    printf("1\n%d",ans);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read();
    if(a[1][1]>=a[1][2])bfs(1);
    for(int i=2;i<m;i++)
        if(a[1][i-1]<=a[1][i]&&a[1][i]>=a[1][i+1])
            bfs(i);
    if(a[1][m]>=a[1][m-1])bfs(m);
    int ans=0;
    for(int i=1;i<=m;i++)
        if(!cov[i])ans++;
    if(ans)printf("0\n%d",ans);
    else tanxin();
    return 0;
}

本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。

转载于:https://www.cnblogs.com/Yzyet/p/7473156.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值