• codevs 1066 引水入城


    /*
    没想到还有dp的事 只能水部分分了
    前几个点可以水过 4,5暴力也可以
    先每个临湖点都灌一下水 (可以加剪枝 比旁边小的可以不搜)
    统计每个临湖点能灌倒几个临沙漠点 并记录每个临沙漠点是否能灌倒
    这样前三个点就好办了 判断可以输出不能全灌到的点
    对于剩下的全部能灌倒得 暴力的话是2^n 也就水两个点了
    这里如果全部能灌倒 有一个很有用的性质 :
    这时每个临水点能灌到的临沙漠点 一定是相邻的一段
    简单反证一下吧
      假设有两段不是连续的 那么不连续的那个部分一定会被越过去(形象点) 
       既然越过去了 介于灌水法的定义 也就是说从这个部分周围走却不覆盖
       那显然不论从那个点开始灌 都覆盖不了 与题意矛盾 假设不成立
    既然连续 那就记录下来 然后开始dp
    显然他是个区间dp 一般的状态f[i][j]显然会爆(再加上枚举起点)
    所以我们定义状态f[i]表示1-i全部覆盖最少几个临湖点 
    转移的话 枚举所有的临湖点 如果合法就更新 最后输出 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 510
    using namespace std;
    int n,m,g[maxn][maxn],sum;
    bool f[maxn][maxn],des[maxn];
    int xx[5]={0,0,0,1,-1};
    int yy[5]={0,1,-1,0,0};
    int dp[maxn];
    struct node
    {
        int l,r,num,falg;
    }p[maxn];
    void Dfs(int x,int y,int k)
    {
        f[x][y]=1;
        if(x==n)
          {
              des[y]=1;
              p[k].falg=1;
              p[k].num++;
              p[k].l=min(p[k].l,y);
              p[k].r=max(p[k].r,y);
          }
        for(int i=1;i<=4;i++)
          {
              int nx=x+xx[i];
              int ny=y+yy[i];
              if(nx>0&&nx<=n&&ny>0&&ny<=m&&f[nx][ny]==0&&g[x][y]>g[nx][ny])
              Dfs(nx,ny,k);
          }
    }
    void DP()
    {
        memset(dp,127/3,sizeof(dp));
        dp[0]=0;
        for(int i=1;i<=m;i++)
          {
              for(int j=1;j<=m;j++)
                {
                    if(!p[j].falg)continue;
                    if(p[j].l<=i&&p[j].r>=i)dp[i]=min(dp[i],dp[p[j].l-1]+1);
              }
          }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
            scanf("%d",&g[i][j]);
        for(int i=1;i<=m;i++)
          {
              p[i].l=maxn+1;
              memset(f,0,sizeof(f));
              Dfs(1,i,i);
          }
        for(int i=1;i<=m;i++)
          if(p[i].num==m)
              {
                printf("1
    1
    ");
                return 0;
            }
        for(int i=1;i<=m;i++)
          if(des[i])sum++;
        if(sum<m)
          {
              printf("0
    %d
    ",m-sum);
              return 0;
          }
        DP();
        printf("1
    %d
    ",dp[m]);
        return 0;
    }
  • 相关阅读:
    核函数基础一简单解释
    矩阵的基本性质 之 正规矩阵,矩阵的迹,行列式,伴随矩阵,矩阵的逆,对角矩阵,矩阵求导
    矩阵的基本性质 之 对称矩阵,Hermite矩阵,正交矩阵,酉矩阵
    矩阵的基本性质 之 矩阵加减法,数乘,乘法,转置
    机器学习实战基础(二十七):sklearn中的降维算法PCA和SVD(八)PCA对手写数字数据集的降维
    拉格朗日对偶性
    批处理符号2
    批处理符号1
    set命令
    goto命令
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/5641519.html
Copyright © 2020-2023  润新知