• 洛谷1514 引水入域 dp+记忆化搜索


    题目链接:https://www.luogu.com.cn/problem/P1514

    题意大致是:给定一个(n,m)的数值矩阵,可以在第一行建造水库,如果一个格子周围的某格子值小于它,那水就可以流到它周围的那个格子,问需要在第一行建造多少水库使得最后一行能够被完全覆盖,如果不能完全覆盖就求出不能覆盖的格子的数量。

    主要思路就是在第一行每个点出发的水能到达第n行的区间可以获得(可以用反证法证明每个点出发的水如果能到达第n行那么它的覆盖区间一定是连续的),如果能够完全覆盖第n行则用最小区间数覆盖可以求出最少需要多少个点可以覆盖第n行,

    代码如下:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef unsigned int ui;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 #define pf printf
     7 #define mem(a,b) memset(a,b,sizeof(a))
     8 #define prime1 1e9+7
     9 #define prime2 1e9+9
    10 #define scand(x) scanf("%llf",&x) 
    11 #define f(i,a,b) for(int i=a;i<=b;i++)
    12 #define scan(a) scanf("%d",&a)
    13 #define dbg(args) cout<<#args<<":"<<args<<endl;
    14 #define pb(i) push_back(i)
    15 #define ppb(x) pop_back(x)
    16 #define inf 0x3f3f3f3f
    17 #define maxn 1005
    18 int n,m,t,a[maxn][maxn],l[maxn][maxn],r[maxn][maxn],vis[maxn][maxn];
    19 //l[i][j]从(i,j)位置出发的水最多能覆盖到最后一行的左端的位置,
    20 //r[i][j]从(i,j)位置出发的水最多能覆盖到最后一行的最右端的位置 
    21 int dir[][2]={{1,0},{0,-1},{-1,0},{0,1}};
    22 void dfs(int x,int y)
    23 {
    24     vis[x][y]=true;//表明(x,y)位置的l,r信息都被处理过 
    25     int xx,yy;
    26     f(i,0,3)
    27     {
    28         xx=x+dir[i][0];
    29         yy=y+dir[i][1];
    30         if(xx<=0||xx>n||yy<=0||yy>m)continue;
    31         if(a[xx][yy]>=a[x][y])continue;
    32         if(!vis[xx][yy])
    33         {
    34             dfs(xx,yy);
    35         }
    36         l[x][y]=min(l[x][y],l[xx][yy]);
    37         r[x][y]=max(r[x][y],r[xx][yy]);
    38     }
    39 }
    40 int main()
    41 {
    42     //freopen("input.txt","r",stdin);
    43     //freopen("output.txt","w",stdout);
    44     std::ios::sync_with_stdio(false);
    45     scan(n);
    46     scan(m);
    47     f(i,1,n)
    48         f(j,1,m)
    49         {
    50             scan(a[i][j]);
    51         }
    52         mem(l,inf);
    53         mem(r,-inf);
    54         f(1,1,m)
    55         {
    56             l[n][i]=r[n][i]=i;//最下面一层,初始情况区间只覆盖自己 
    57         }
    58         f(i,1,m)
    59         {
    60             if(!vis[1][i])
    61             dfs(1,i);
    62         }
    63         bool  flag=true;
    64         int cnt=0;
    65         f(i,1,m)
    66         {
    67             if(!vis[n][i])
    68             {
    69                 flag=false;
    70                 cnt++;
    71             }
    72         }
    73         if(!flag)
    74         {
    75             pf("0
    %d",cnt);//有多少个点无法覆盖 
    76         }
    77         else 
    78         {
    79             int num=0;
    80             int left=1,maxr=0;//最小区间数覆盖 
    81             while(left<=m)
    82             {
    83                 maxr=0;
    84                 f(i,1,m)
    85                 {
    86                     if(l[1][i]<=left)//找到覆盖left点的区间右端值的最大值 
    87                     maxr=max(maxr,r[1][i]);
    88                 }
    89                 left=maxr+1;
    90                 num++;
    91              } 
    92             pf("1
    %d
    ",num);
    93         /*    f(i,1,m)
    94             {
    95                 pf("%d %d
    ",l[1][i],r[1][i]);
    96             }*/
    97         }
    98         return 0;
    99  } 
  • 相关阅读:
    Moss2010 部署命令
    socket形象描述
    Android UI 的更新
    android AIDL 进程间通信
    中文设置成粗体的方法
    android 主件之 Service
    android activity
    拦截Activity的后退键处理
    android 解析json数据格式
    防止事件导致的oncreate的多次调用
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12390429.html
Copyright © 2020-2023  润新知