zoukankan      html  css  js  c++  java
  • POJ 3254 Corn Fields(DP + 状态压缩)

    题目链接:http://poj.org/problem?id=3254

    题目大意:Farmer John 放牧cow,有些草地上的草是不能吃的,用0表示,然后规定两头牛不能相邻放牧。问你有多少种放牧方法。

    Sample Input

    2 3
    1 1 1
    0 1 0

    Sample Output

    9

    分析:对于这种二维地图型,一般设状态dp[i][j]表示第 i 行第 j 状态达到要求的总数

      输入地图,用map[i]表示第 i 行中的状态。为了是sta[k]表示可行状态更加方便,map[i]中用0表示可放牧,1表示不可放牧,这样如果(sta[k]&map[i]==0)则说明满足放牧要求。

      动态规划:初始化:令dp[0][j]中可以在第一行放牧的状态j,dp[0][j]=1;

          转移方程:dp[i][j] = dp[i][j] + dp[i-1][k],k为所有满足条件的状态

    代码如下:

     1 # include<stdio.h>
     2 # include<string.h>
     3 const int MAXN = 1<<12;
     4 const int MOD = 100000000;
     5 int sta[MAXN],num;        
     6 int dp[13][MAXN];    //dp[i][j]表示第i行在集合j中满足条件的方案数
     7 int map[13];    //表示输入中每一行的状态
     8 int n,m;    
     9 void init(){
    10     num =0;
    11     int sum = 1<<m;
    12     for(int i=0; i<sum;i++)    //从1到sum里边有满足该状态中放牛的位置不相邻的方案有num个
    13         if(i&(i<<1))
    14             continue;
    15         else
    16             sta[num++] = i;
    17 }
    18 
    19 void DP(){
    20     int i,j,k;
    21     for(i=0; i<num; i++)
    22         if(!(sta[i]&map[0]))    //寻找第一层满足条件的方案,令它为1
    23             dp[0][i] = 1;
    24         for(i=1; i<n; i++)
    25             for(j=0; j<num; j++)    //第i行是状态j
    26                 if(sta[j]&map[i])    //去掉与草场矛盾
    27                     continue;
    28                 else
    29                     for(k=0; k<num; k++){        //第i-1行是状态k
    30                         if(map[i-1]&sta[k])        //去掉与草场矛盾的
    31                             continue;
    32                         if(sta[k]&sta[j])        //去掉与上一行状态矛盾的
    33                             continue;
    34                         dp[i][j] = (dp[i][j] + dp[i-1][k]) % MOD;
    35                     }
    36         int ans = 0;
    37         for(i=0; i<num; i++)
    38             ans = (ans+dp[n-1][i])%MOD;
    39         printf("%d
    ",ans);
    40 }
    41 int main(){
    42     int i,j,temp;
    43     while(scanf("%d%d",&n,&m)!=EOF){
    44         memset(map,0,sizeof(map));
    45         for(i=0; i<n; i++)
    46             for(j=0; j<m; j++){
    47                 scanf("%d",&temp);
    48                 if(temp==0)        //将每行状态二进制表示,1代表题目中的0,代表1
    49                     map[i] += 1<<(m-j-1);
    50             }
    51         init();
    52         DP();
    53     }
    54     return 0;
    55 }

     也可以使用滚动数组:

     1 # include<stdio.h>
     2 # include<string.h>
     3 const int MAXN = 1<<12;
     4 const int MOD = 100000000;
     5 int sta[MAXN],num;
     6 int dp[2][MAXN];    //dp[i][j]表示第i行在集合j中满足条件的方案数
     7 int map[13];    //表示输入中每一行的状态
     8 int n,m;
     9 void init(){
    10     num =0;
    11     int sum = 1<<m;
    12     for(int i=0; i<sum;i++)    //从1到sum里边有满足该状态中放牛的位置不相邻的方案有num个
    13         if(i&(i<<1))
    14             continue;
    15         else
    16             sta[num++] = i;
    17 }
    18 
    19 void DP(){
    20     int i,j,k;
    21     memset(dp,0,sizeof(dp));
    22     for(i=0; i<num; i++)
    23         if(!(sta[i]&map[0]))    //寻找第一层满足条件的方案,令它为1
    24             dp[0][i] = 1;
    25     for(i=1; i<n; i++){
    26         for(j=0; j<num; j++)  {  //第i行是状态j
    27             dp[i%2][j] = 0;      //用来初始化,在滚动数组里边很重要
    28             if(sta[j]&map[i])    //去掉与草场矛盾
    29                 continue;
    30             else
    31                 for(k=0; k<num; k++){        //第i-1行是状态k
    32                     if(map[i-1]&sta[k])        //去掉与草场矛盾的
    33                         continue;
    34                     if(sta[k]&sta[j])        //去掉与上一行状态矛盾的
    35                         continue;
    36                     dp[i%2][j] = (dp[i%2][j] + dp[(i+1)%2][k]) % MOD;
    37                 }
    38         }
    39     }
    40     int ans = 0;
    41     int temp = (n+1)%2;
    42     for(i=0; i<num; i++)
    43         ans = (ans+dp[temp][i])%MOD;
    44     printf("%d
    ",ans);
    45 }
    46 int main(){
    47     int i,j,temp;
    48     while(scanf("%d%d",&n,&m)!=EOF){
    49         memset(map,0,sizeof(map));
    50         for(i=0; i<n; i++)
    51             for(j=0; j<m; j++){
    52                 scanf("%d",&temp);
    53                 if(temp==0)        //将每行状态二进制表示,1代表题目中的0,代表1
    54                     map[i] += 1<<(m-j-1);
    55             }
    56         init();
    57         DP();
    58     }
    59     return 0;
    60 }
  • 相关阅读:
    leveldb实现类sql查询
    系统设计
    Code Complete
    工具 VSCode快捷键
    C/C++ extern
    C/C++ 宏字符串拼接
    【Java】字符串
    【Java】常用类-sysytem-math
    【Java】枚举
    【Java】内部类
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3300249.html
Copyright © 2011-2022 走看看