• [ GDOI 2014 ] 拯救莫莉斯


    (\)

    (Description)


    有一个 (N imes M) 的网格,每个格点都有权值,图是四连通的。

    现在选择一个点集,使得每个格点要么被选中,要么连通的点之一被选中。

    求这个点集的权值和最小值,在保证前两条满足的前提下,点集大小最小是多少。

    • (N imes Mle 50, Mle N)

    (\)

    (Solution)


    状压入门题目。

    注意到在题面的限制条件下,(M) 最大是(7),我们不妨状压每一行的情况。

    注意一个方案里一行合法的要求,那就是上、下、本行和本行左右移的方案或起来得到的二进制位是满的。

    那么我们状态里就不能只记录当前行了,因为无法确定是否合法。

    (f[i][S][S_1]) 表示第 (i) 行放置方案为 (S) ,第 (i-1) 行放置方案为 (S_1)(i-1) 行都合法的前提下 的最优解。

    那么注意到一行的确定是由三行确定的,所以我们需要枚举行数 (i) ,第 (i-2) 行的放置情况 (S_2) ,第 (i-1) 行的放置情况 (S_1) ,第 (i) 行的放置情况 (S) ,转移条件自然是

    [S_2|S_1|(S_1<<1)|(S_1>>1)|S ge (1<<M)-1 ]

    然后状态维护一个结构体,手写一个结构体取 (min) 就好了。

    注意初始化,有答案的应该只有 (f[1][k][0]),其他都要置成 (inf)

    注意答案的选取,合法的答案需要满足 (S_1|S|(S<<1)|(S>>1) ge (1<<M)-1)

    同行左右移的辅助一开始忘记了,状态压缩类型的题目还是要注意考虑全面。

    (\)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 51
    #define R register
    #define gc getchar
    #define inf 2000000000
    using namespace std;
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    int n,m,lim,mp[N][10],cost[N][1<<8],cnt[1<<8];
    
    struct dp{int w,cnt;}f[N][1<<8][1<<8],ans;
    
    inline dp mn(dp x,dp y){
      if(x.w!=y.w) return (x.w<y.w)?x:y;
      return (x.cnt<y.cnt)?x:y;
    }
    
    int main(){
      n=rd(); m=rd(); lim=(1<<m)-1;
      for(R int i=1;i<=n;++i)
        for(R int j=0;j<m;++j) mp[i][j]=rd();
      for(R int i=1;i<=n;++i)
        for(R int j=0;j<=lim;++j)
          for(R int k=0;k<m;++k) if(j&(1<<k)) cost[i][j]+=mp[i][k];
      for(R int i=0;i<=lim;++i)
        for(R int j=0;j<m;++j) if(i&(1<<j)) ++cnt[i];
      for(R int i=0;i<=n;++i)
        for(R int s=0;s<=lim;++s)
          for(R int s1=0;s1<=lim;++s1)
            f[i][s][s1].w=f[i][s][s1].cnt=inf;
      for(R int i=0;i<=lim;++i){
        f[1][i][0].w=cost[1][i];
        f[1][i][0].cnt=cnt[i];
      }
      for(R int i=2;i<=n;++i)
        for(R int s=0;s<=lim;++s)
          for(R int s1=0;s1<=lim;++s1)
            for(R int s2=0;s2<=lim;++s2)
              if(((s|s1|s2|(s1<<1)|(s1>>1))&lim)==lim)
                f[i][s][s1]=mn(f[i][s][s1],(dp){f[i-1][s1][s2].w+cost[i][s],f[i-1][s1][s2].cnt+cnt[s]});
      ans.w=ans.cnt=inf;
      for(R int s1=0;s1<=lim;++s1)
        for(R int s2=0;s2<=lim;++s2)
          if(((s1|s2|(s1<<1)|(s1>>1))&lim)==lim) ans=mn(ans,f[n][s1][s2]);
      printf("%d %d",ans.cnt,ans.w);
      return 0;
    }
    
    
    
  • 相关阅读:
    AndroidManifest.xml文件详解(activity)(二)
    Android Studio显示可视化编辑界面
    Delphi XE2 新增 System.Zip 单元,压缩和解压缩文件
    LockBox的安装
    Kernel的意义
    Mathematical optimization数学上的最优化
    矩阵分析
    【2008nmj】支持向量机
    【2008nmj】BP二元分类
    【2008nmj】Logistic回归二元分类感知器算法.docx
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9816293.html
Copyright © 2020-2023  润新知