zoukankan      html  css  js  c++  java
  • HDU2167 Pebbles(状压DP)

    题目给一张n×n的格子,每个格子都有数字,要从格子中取若干个数字,八个方向相邻的数字不能一起取,问取的数字最大和是多少。

    从第一行一行一行看下去,可以发现第1行取哪几列只会影响到第2行,第3行后面的一点影响都没有。即第i行的决策只受i-1行决策的影响。

    那么自然想到状态DP——

    • dp[i][S]前i行其中第i行取的列的集合是S的取数最大和
    • dp[i][S]=max(dp[i-1][S'])+集合S数字和(S是S'的合法的下一行的取法)

    虽然题目n最多15,集合S就215种状态,但事实上合法的(不能同时取同一行相邻的两列数字)集合S状态只有1000多个。枚举即可转移,为了保证时间复杂度做一些预处理就行了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<vector>
     4 #include<algorithm>
     5 using namespace std;
     6 int read(char *&s){
     7     int res=-1;
     8     sscanf(s,"%d",&res);
     9     while(*s==' ') ++s;
    10     while(*s>='0' && *s<='9') ++s;
    11     while(*s==' ') ++s;
    12     return res;
    13 }
    14 int n,a[15][15],d[15][1<<15],sta[1<<15],sn;
    15 bool isok(int s){
    16     for(int i=1; i<n; ++i){
    17         if(((s>>i-1)&1) && ((s>>i)&1)) return 0;
    18     }
    19     return 1;
    20 }
    21 bool isok(int x,int y){
    22     for(int i=0; i<n; ++i){
    23         if(((x>>i)&1)==0) continue;
    24         if((y>>i)&1) return 0;
    25         if(i>0 && ((y>>i-1)&1)) return 0;
    26         if(i<n-1 && ((y>>i+1)&1)) return 0;
    27     }
    28     return 1;
    29 }
    30 int main(){
    31     char str[1111];
    32     while(gets(str) && *str){
    33         n=0;
    34         char *s=str; int t;
    35         while(t=read(s),t!=-1) a[0][n++]=t;
    36         for(int i=1; i<n; ++i){
    37             gets(str); s=str;
    38             for(int j=0; j<n; ++j) a[i][j]=read(s);
    39         }
    40         sn=0;
    41         for(int i=0; i<(1<<n); ++i){
    42             if(isok(i)) sta[sn++]=i; 
    43         }
    44         memset(d,0,sizeof(d));
    45         for(int i=0; i<sn; ++i){
    46             for(int j=0; j<n; ++j){
    47                 if((sta[i]>>j)&1) d[0][sta[i]]+=a[0][j];
    48             }
    49         }
    50         vector<int> vec[2222];
    51         for(int i=0; i<sn; ++i){
    52             for(int j=0; j<sn; ++j){
    53                 if(isok(sta[i],sta[j])) vec[i].push_back(j);
    54             }
    55         }
    56         for(int i=1; i<n; ++i){
    57             for(int j=0; j<sn; ++j){
    58                 for(int k=0; k!=vec[j].size(); ++k) d[i][sta[j]]=max(d[i][sta[j]],d[i-1][sta[vec[j][k]]]);
    59                 for(int k=0; k<n; ++k){
    60                     if((sta[j]>>k)&1) d[i][sta[j]]+=a[i][k];
    61                 }
    62             }
    63         }
    64         int res=0;
    65         for(int i=0; i<sn; ++i){
    66             res=max(res,d[n-1][sta[i]]);
    67         }
    68         printf("%d
    ",res);
    69         getchar();
    70     }
    71     return 0;
    72 } 
  • 相关阅读:
    DIV 设置垂直居中
    JavaScript--什么是函数
    JavaScript--引用JS外部文件
    JavaScript--如何插入JS
    CSS-类和ID选择器的区别
    CSS-ID选择器
    CSS类选择器
    CSS样式介绍
    HTML--使用mailto在网页中链接Email地址
    HTML--form表单中的label标签
  • 原文地址:https://www.cnblogs.com/WABoss/p/5188403.html
Copyright © 2011-2022 走看看