標籤:style blog http color os io for ar
題目:http://poj.org/problem?id=3254
因為&運算寫成&&--導致調試了快一個小時代的代碼沒有搞定
關於建圖:
1、題目中是1表示可以放牧,0表示不可以放牧,但是建圖的時候,可以放牧的位用0表示,不可以放牧的位用1表示。原因如下:
假設可以放牧的位用1表示,不可以放牧的位用0表示,那麼假設當前行狀態時1010 想要放置1001 ,&運算的結果是1,但是顯然不合法,
也就是說 設值狀態的意義,以及怎麼判斷是不是合法,這個在做之前一定考慮清楚再去寫,否則改起來很麻煩
如果可以放牧的位用0表示,不可以放牧的位用1表示,那麼,合法狀態與圖的狀態想與的結果都是0,從而判斷狀態
2、由於狀態非常多,所以最初儲存所有狀態的時候,就要去除一部分不合法的狀態--相鄰位不能為同為1 ,就是(x&(x<<1))不能為1
3、dp[i][j]=segma(dp[i-1][k]) dp[i][j]表示當前設定到第i行,狀態為j的方案數, 計算方法是枚舉第i-1行的狀態,對每一種,枚舉第i行的狀態
帖代碼:
#include <cstdio>#include <iostream>#include <cstring>using namespace std;#define rep(i,s,e) for(int i=s;i<e;i++)#define repe(i,s,e) for(int i=s;i<=e;i++)#define reped(i,s,e) for(int i=s;i>=e;i--)#define arclr(aa,v) memset(aa,v,sizeof(aa))#define ll long long#define IN(s) freopen(s, "r", stdin)const int MAXN = 17;//注意int只有32位const int MOD = 100000000;int state[MAXN],mat[MAXN][MAXN];int all[1<<MAXN],scnt;//記錄所有可能的狀態用於枚舉ll dp[MAXN][1<<MAXN];int n,m;void init(){ scnt=0;//所有可能的狀態總數 int tot= (1<<n); for(int i=0;i<tot;i++) if(!(i & i<<1))//要求相鄰不能有1 牛與牛之間不能相鄰 all[scnt++]=i;//儲存所有可能的狀態,上一個條件排除了很多狀態 memset(dp,0,sizeof(dp));}int main(){ //IN("poj3254.txt"); while(~scanf("%d%d",&m,&n)) { init(); for(int i=1;i<=m;i++) { state[i]=0;//初始化第i行的狀態,0可以放牧,1表示不能放牧 for(int j=1;j<=n;j++) { scanf("%d",&mat[i][j]); if(!mat[i][j])state[i]+=(1<<(n-j)); } } //初始化dp邊界 for(int i=0;i<scnt;i++) if(!(all[i]&state[1])) dp[1][i]=1; for(int i=2;i<=m;i++) { for(int j=0;j<scnt;j++) { if((all[j]&state[i]))continue;// 牛必須放在方格1裡 for(int k=0;k<scnt;k++) { if((all[k]&state[i-1]))continue;//牛必須放在方格1裡 if( all[k]&all[j] )continue;//不能有兩個1在同一列,兩隻牛也不能豎著相鄰 dp[i][j]=(dp[i][j]+dp[i-1][k])%MOD;// } } } ll ans=0; for(int i=0;i<scnt;i++) { ans=(ans+dp[m][i])%MOD; } printf("%lld\n",ans); } return 0;}