Luogu P1514 引水入城

我承认我有点懒(洛谷已经发过题解了,但我发誓要坚持写博客)

这道题坑了我3天……

首先一看就与染色问题类似,果断BFS(写DFS炸了)

先将最上面(靠近水)的一行全部扔进队列里,做一遍BFS

再对最下面(远离水)的一行进行扫描,如果发现有点搜索不到,输出0并统计个数退出(很好说明:如果全部修建都无法完成那么使用更少的点是不可能的)

如果可以,就进行第二遍BFS

把第一行每个点分别扔进队列,搜索出它在最下面的可以供水的区间

等等,为什么是区间?

这个很好证明,有多位大佬已经详细证明,我简单说一下

如果这个区间间断了,那么这个间断的点就会比周围的点海拔都高,那么就会产生无解的情况,因为已经证明有解,所以不可能出现这种情况

所以,我们统计所有的区间,做一遍区间覆盖即可

方法很多,DP或者贪心

我打的是贪心,记录最优的区间尾端点

具体看代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define maxn 505
using namespace std;
inline void read(int &x)
{
    x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
struct data
{
    int x,y;
}a[maxn]; //记录区间
int comp(data a,data b) { return a.x<b.x; }
const int fx[4]={0,1,0,-1},fy[4]={1,0,-1,0};
int map[maxn][maxn],n,m,i,j,q[maxn*maxn*2+10][2],tot,ans,k,t1,t2;
bool f[maxn][maxn],flag=0;
int main()
{
    read(n); read(m);
    for (i=1;i<=n;++i)
    for (j=1;j<=m;++j)
    read(map[i][j]);
    memset(f,true,sizeof(f));
    int head=0,tail=0;
    for (j=1;j<=m;++j)
    f[1][j]=0,q[++tail][0]=1,q[tail][1]=j;
    while (head++<tail) //第一遍BFS判断是否有解
    {
        for (i=0;i<4;++i)
        {
            int xx=q[head][0]+fx[i],yy=q[head][1]+fy[i];
            if (f[xx][yy]&&xx>0&&yy>0&&xx<=n&&yy<=m&&map[xx][yy]<map[q[head][0]][q[head][1]])
            {
                f[xx][yy]=0;
                q[++tail][0]=xx; q[tail][1]=yy;
            }
        }
    }
    for (j=1;j<=m;++j)
    if (f[n][j]) { flag=1; tot++; }
    if (flag)
    {
        puts("0");
        printf("%d",tot);
        return 0;
    }
    for (j=1;j<=m;++j) //对每个点都做一遍BFS,由于数据不大,可以水过
    {
        memset(f,true,sizeof(f));
        f[1][j]=0;
        head=0; tail=1;
        q[1][0]=1; q[1][1]=j;
        while (head++<tail)
        {
            for (i=0;i<4;++i)
            {
                int xx=q[head][0]+fx[i],yy=q[head][1]+fy[i];
                if (f[xx][yy]&&xx>0&&xx<=n&&yy>0&&yy<=m&&map[xx][yy]<map[q[head][0]][q[head][1]])
                {
                    q[++tail][0]=xx; q[tail][1]=yy;
                    f[xx][yy]=0;
                }
            }        
        }
        t1=t2=0;
        for (i=1;i<=m;++i)
        if (!f[n][i]) { t1=i; break; }
        if (!t1) continue;
        for (;i<=m+1;++i)
        if (f[n][i]) { t2=i-1; break; }
        a[++k].x=t1; a[k].y=t2; //记录可以到达的区间
    }
    sort(a+1,a+k+1,comp);
    puts("1");
    i=1; int last=1;
    while (last<=m)
    {
        int t=0;
        while (a[i].x<=last) t=max(a[i++].y,t);
        last=t+1; ans++;
    } //贪心跑一遍区间覆盖模板
    printf("%d",ans);
    return 0;
}

难度不大吧,就是很

辣鸡老年选手AFO在即
原文地址:https://www.cnblogs.com/cjjsb/p/7886809.html