• 状压dp入门第一题 poj3254


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

    转自http://blog.csdn.net/harrypoirot/article/details/23163485

     1 #include <stdio.h>
     2 #include <math.h>
     3 #include <string.h>
     4 #include <stdlib.h>
     5 #include <iostream>
     6 #include <sstream>
     7 #include <algorithm>
     8 #include <string>
     9 #include <queue>
    10 #include <vector>
    11 using namespace std;
    12 const int maxn= 1e5 + 10;
    13 const int inf = 0x3f3f3f3f;
    14 typedef long long ll;
    15 #define mod 100000000
    16 int M,N,top = 0;
    17 //top表示每行最多的状态数
    18 
    19 int state[600],num[110];  
    20 //state存放每行所有的可行状态(即没有相邻的状态
    21 //
    22 
    23 int dp[20][600];
    24 //dp[i][j]:对于前i行数据,每行有前j种可能状态时的解
    25 int cur[20];
    26 //cur[i]表示的是第i行整行的情况
    27 
    28 inline bool ok(int x){    //判断状态x是否可行
    29    if(x&x<<1)    return false;//若存在相邻两个格子都为1,则该状态不可行
    30    return true;
    31 }
    32 void init(){            //遍历所有可能的状态
    33    top = 0;
    34    int total = 1 << N; //遍历状态的上界
    35    for(int i = 0; i < total; ++i){
    36        if(ok(i))state[++top] = i;    
    37    }
    38 }
    39 inline bool fit(int x,int k){ //判断状态x 与第k行的实际状态的逆是否有‘重合’
    40    if(x&cur[k])return false; //若有重合,(即x不符合要求)
    41    return true;  //若没有,则可行
    42 }
    43 
    44 int main(){
    45     while(scanf("%d%d",&M,&N)!= EOF){
    46        init();
    47        memset(dp,0,sizeof(dp));
    48        for(int i = 1; i <= M; ++i){
    49            cur[i] = 0;
    50            int num;
    51            for(int j = 1; j <= N; ++j){  //输入时就要按位来存储,cur[i]表示的是第i行整行的情况,每次改变该数字的二进制表示的一位
    52                 scanf("%d",&num);  //表示第i行第j列的情况(0或1)
    53                if(num == 0) //若该格为0    
    54                    cur[i] +=(1<<(N-j)); //则将该位置为1(注意要以相反方式存储,即1表示不可放牧
    55            }
    56        }
    57        for(int i = 1;i <= top;i++){
    58            if(fit(state[i],1)){  //判断所有可能状态与第一行的实际状态的逆是否有重合
    59                 dp[1][i] = 1;  //若第1行的状态与第i种可行状态吻合,则dp[1][i]记为1
    60            }
    61        
    62        }
    63 
    64        /*
    65        状态转移过程中,dp[i][k] =Sigma dp[i-1][j] (j为符合条件的所有状态)
    66         */
    67        for(int i = 2; i <= M; ++i){  //i索引第2行到第M行
    68            for(int k = 1; k <= top; ++k){ //该循环针对所有可能的状态,找出一组与第i行相符的state[k]
    69                 if(!fit(state[k],i))continue; //判断是否符合第i行实际情况
    70                 for(int j = 1; j <= top ;++j){ //找到state[k]后,再找一组与第i-1行符合,且与第i行(state[])不冲突的状态state[j]
    71                    if(!fit(state[j],i-1))continue;  //判断是否符合第i-1行实际情况
    72                    if(state[k]&state[j])continue;  //判断是否与第i行冲突
    73                    dp[i][k] = (dp[i][k] +dp[i-1][j])%mod;  //若以上皆可通过,则将'j'累加到‘k'上
    74                 }
    75            }
    76        }
    77        int ans = 0;
    78        for(int i = 1; i <= top; ++i){ //累加最后一行所有可能状态的值,即得最终结果!!!泥马写注释累死我了终于写完了!
    79            ans = (ans + dp[M][i])%mod;
    80        }
    81        printf("%d
    ",ans);
    82    }
    83 }
  • 相关阅读:
    17.正则表达式
    16.os模块-shutil模块-tarfile压缩模块
    15.序列化模块-时间模块-zip压缩模块
    第一章 单变量线性回归
    如何跑通MonoRTM模型的官方例子
    PHP命名规范
    js中要声明变量吗?
    php抓取网站图片源码
    InnoDB和MyISAM区别总结
    php分页代码。
  • 原文地址:https://www.cnblogs.com/stranger-/p/7482161.html
Copyright © 2020-2023  润新知