zoukankan      html  css  js  c++  java
  • NOIP 2010 P1514 引水入城

    题目:传送门

    题目概要:有一个n行m列的矩阵,每一个格子都有一个高度,路径只能从高处向低处扩散,问你如果最后一行可以全部被覆盖,最少要从第一行多少个格子开始,如果不能使最后一行全部被覆盖,求有多少个格子不能;

    看完这道题,最直接的想法就是直接定义dx,dy两个数组表示上下左右走,看看第一行每一个格子能对应多少个最后一行的格子。

    然后再设置一个vis数组表示最后一行是否已经被到达过,如果最后一行有点还没有被到达过,就输出0和vis=0的格子数量

    但是当我们想要实现的时候,发现如果第一行的某个点对应的最后一行的点是断断续续的,那就很舒(e)服(xin)了

    buuuut~

    似乎可以证明,对于每一个第一行的点,他所对应的最后一行的点总是连续的

    反证法:假设可以不连续

    我们来看图

    如图,这是一条从上到下的连续的路径,用红色标记

     现在我们假设从第一行开始有这么一条路径不连续,如图,用蓝色表示

     我们会发现,这样的话一定会有重合的路径,用紫色表示

    既然这样,从第一行蓝色点出发也一定能够到达最下层的红色点

    那么最下面一行的区间一定是连续的,证毕(这里不连续是因为有无解的情况)

    有了这个结论,只要不是无解的情况,把最后一行的连续区间拿出来,就变成了一个线段覆盖问题

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<string>
     7 #include<queue>
     8 #include<stack>
     9 #include<time.h>
    10 using namespace std;
    11 typedef long long ll;
    12 ll read(){
    13     ll ans=0;
    14     char last=' ',ch=getchar();
    15     while(ch<'0' || ch>'9')last=ch,ch=getchar();
    16     while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    17     if(last=='-')ans=-ans;
    18     return ans;
    19 }
    20 
    21 const int maxn=501;
    22 
    23 int n,m,atlas[maxn][maxn];
    24 int num[maxn][maxn];
    25 bool vis[maxn][maxn];
    26 int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
    27 int l[maxn][maxn],r[maxn][maxn];
    28 
    29 //记忆化搜索 
    30 void dfs(int x,int y)
    31 {
    32     vis[x][y]=true;//先标记这个点到达过 
    33     for(int i=0;i<4;i++)//上下左右搜索 
    34     {
    35         int nx=x+dx[i],ny=y+dy[i];
    36         if(nx<1||nx>n||ny<1||ny>m) continue;//判断边界 
    37         if(atlas[nx][ny]>=atlas[x][y]) continue;//判断高度 
    38         if(!vis[nx][ny])dfs(nx,ny);
    39         l[x][y]=min(l[x][y],l[nx][ny]);
    40         r[x][y]=max(r[x][y],r[nx][ny]);//更新区间左右端点 
    41     }
    42 }
    43 
    44 int main()
    45 {
    46     n=read(),m=read();
    47     memset(vis,false,sizeof(vis));
    48     memset(l,0x3f,sizeof(l));//初始化 
    49     for(int i=1;i<=m;i++)
    50     {
    51         l[n][i]=r[n][i]=i;//区间初始化 
    52     }
    53     for(int i=1;i<=n;i++)
    54     {
    55         for(int j=1;j<=m;j++)
    56         {
    57             atlas[i][j]=read();
    58         }
    59     }
    60     
    61     for(int i=1;i<=m;i++)
    62     {
    63         if(!vis[1][i]) dfs(1,i);//如果还没有被到达过,就搜索 
    64     }
    65     
    66     int counti=0;
    67     for(int i=1;i<=m;i++)
    68     {
    69         if(!vis[n][i]) counti++;
    70     }//看最后一行有没有不能到达的 
    71     if(counti!=0) 
    72     {
    73        cout<<0<<endl<<counti;
    74        return 0;
    75     }
    76     
    77     int left=1;//记录当前最左边的点 
    78     while (left<=m)//跑一遍区间覆盖 
    79     {
    80         int maxr=0;
    81         for (int i=1;i<=m;i++)
    82             if (l[1][i]<=left)//如果这个点在区间左端点的右边 
    83                 maxr=max(maxr,r[1][i]);//寻找右端点最大的 
    84         counti++;
    85         left=maxr+1;//继续更新 
    86     }
    87     cout<<1<<endl<<counti;
    88     return 0;
    89 }
  • 相关阅读:
    ERROR: Couldn't connect to Docker daemon at http+docker://localunixsocket
    plainless script for es
    canal 代码阅读
    elasticsearch 之编译过程
    nfs 共享目录
    canal mysql slave
    yum 运行失败
    linux 几种服务类型
    2019-04-16 SpringMVC 学习笔记
    2019-04-10 集成JasperReport
  • 原文地址:https://www.cnblogs.com/lcezych/p/10821902.html
Copyright © 2011-2022 走看看