状压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\n",ans);
82    }
83 }
时间: 2024-10-14 23:35:05

状压dp入门第一题 poj3254的相关文章

POJ3254 状压DP入门

题目:http://poj.org/problem?id=3254 因为&运算写成&&--导致调试了快一个小时代的代码没有搞定 关于建图: 1.题目中是1表示可以放牧,0表示不可以放牧,但是建图的时候,可以放牧的位用0表示,不可以放牧的位用1表示.原因如下: 假设可以放牧的位用1表示,不可以放牧的位用0表示,那么假设当前行状态时1010   想要放置1001 ,&运算的结果是1,但是显然不合法, 也就是说  设值状态的意义,以及怎么判断是不是合法,这个在做之前一定考虑清楚再

poj 3254 Corn Fields 状压dp入门

// poj3254 状压dp入门 // dp[i][S]表示前i行第i行状态为S时放牧的情况 // S为十进制的二进制数形式如5为101表示第一列和第三列放牧的方法数 // 首先dp[0][S]合法的话就是1 // 状态转移方程为dp[i][S] = sigma(dp[i-1][V])(S与V是合法状态) // 最后的结果就是dp[n][S](S为所有的合法状态) // // 刚开始十分傻x的dp[0][S]置为get(S),...get(S)是其中1的个数 // 这又不是求放羊的数量,这是方

poj 2411 Mondriaan&#39;s Dream 状压dp入门

题意: 求h*w的矩形被1*2的小矩形覆盖的方案数. 分析: 状压dp入门,<挑战程序设计竞赛>上讲的很好,好几天才看懂. 代码: #include <iostream> using namespace std; __int64 ans[16][16]; int n,m; __int64 dp[2][1<<16]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*n

状压DP入门——铺砖块

题目描述 现有n*m的一块地板,需要用1*2的砖块去铺满,中间不能留有空隙.问这样方案有多少种 输入 输入n,m(1<=n, m<=11) 有多组输入数据,以m=n=0结束 输出 输出铺砖块的方案数 样例输入 1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0 样例输出 1 0 1 2 3 5 144 51205 我A的第一道状压DP题是导游,感觉就是背包~~ 此题不是很懂 此题状压DP,DP[i][sta]表示前i行填满对第i+1行的影响为状态sta时的方案总数 易知

状压dp入门

(先处理好基本的位运算的东西) 为了更好的理解状压dp,首先介绍位运算相关的知识. 1.'&'符号,x&y,会将两个十进制数在二进制下进行与运算,然后返回其十进制下的值.例如3(11)&2(10)=2(10). 2.'|'符号,x|y,会将两个十进制数在二进制下进行或运算,然后返回其十进制下的值.例如3(11)|2(10)=3(11). 3.'^'符号,x^y,会将两个十进制数在二进制下进行异或运算,然后返回其十进制下的值.例如3(11)^2(10)=1(01). 4.'<&

POJ 1185 炮兵阵地(状压DP入门)

http://poj.org/problem?id=1185 状压DP: 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int dp[105][100][100]; 7 int ma[105],st[105]; 8 9 int ok(int x) 10 { 11 return (x&(x<<1))+(x&(x&

poj 2441 Arrange the Bulls(状压DP入门)

Arrange the Bulls Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 3509   Accepted: 1344 Description Farmer Johnson's Bulls love playing basketball very much. But none of them would like to play basketball with the other bulls because the

poj 2441 Arrange the Bulls 状压dp入门

题意: 将n头牛和m个栏做匹配,求匹配方案数. 分析: 开始暴搜tle了,还是要用状压dp,dp[i][s]表示前i头牛匹配栏的状态为s时可行的方案数. 代码: //poj 2441 //sep9 #include <iostream> using namespace std; const int maxN=21; int dp[2][1<<maxN]; int a[maxN][maxN]; int main() { int n,m; scanf("%d%d",

poj 3254 状压dp入门题

1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相邻,求有多少种放法. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #d