• 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在即
  • 相关阅读:
    Android中的进程
    简单解析三种JAVA调用方式-同步,异步,回调
    Android BroadCastReceiver介绍
    Android 消息处理机制-Looper,Handler,MessageQueue
    Android onPause 和onSaveInstanceState
    Android finish后没有执行 onDestory()
    自定义Linearlayout
    python学习笔记一
    笔试题目汇总
    互联网_http协议
  • 原文地址:https://www.cnblogs.com/cjjsb/p/7886809.html
Copyright © 2020-2023  润新知