poj3254二進制放牛——狀態壓縮DP
阿新 • • 發佈:2018-02-23
true 上界 pos csharp targe pac 狀態 二進制 arp
題目:http://poj.org/problem?id=3254
利用二進制壓縮狀態,每一個整數代表一行的01情況;
註意預處理出二進制表示下沒有兩個1相鄰的數的方法,我的方法(不知為何)錯了,看到了別人的優美方法;
再進行DP即可。
代碼如下:
#include<iostream> #include<cstdio> using namespace std; int m,n,a[15],num[15],p[3005],f[15][3005],tot,INF=100000000,ans; //int pw(int w) //{ // int ret=1; // int sum=1; // while(w) // { // ret*=2; // if(w&1)sum*=ret; // w/=2; // } // return sum; //} //void ap(int w,int b,int jl)//2^w b=0/1 +jl //{ // if(w==n-1) // { // if(!b)p[++tot]=jl; // else // { // p[++tot]=jl; // p[++tot]=jl+pw(w); // } // return; // } // if(!b)ap(w+1,1,jl); // else // { // ap(w+1,0,jl+pw(w)); // ap(w+1,1,jl); // } //} inline bool ok(int x){ //判斷狀態x是否可行 if(x&x<<1) return false;//若存在相鄰兩個格子都為1,則該狀態不可行 return true; } void init(){ //遍歷所有可能的狀態 int total = 1 << n; //遍歷狀態的上界 for(int i = 0; i < total; ++i){ if(ok(i))p[++tot] = i; } } int main() { scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { scanf("%d",&a[j]); num[i]*=2; num[i]+=a[j]; } init(); // ap(0,1,0); // cout<<tot<<endl; for(int i=1;i<=tot;i++) { // cout<<p[i]<<endl; if(!(p[i]&(~num[1])))f[1][i]++; } for(int i=2;i<=m;i++) { for(int j=1;j<=tot;j++) { if(p[j]&(~num[i-1]))continue; for(int k=1;k<=tot;k++) { if((p[k]&(~num[i]))||(p[k]&p[j]))continue; f[i][k]+=f[i-1][j]; f[i][k]%=INF; } } } for(int i=1;i<=tot;i++) { ans+=f[m][i]; ans%=INF; } printf("%d",ans); return 0; }
poj3254二進制放牛——狀態壓縮DP