Corn Fields
poj3254:http://poj.org/problem?id=3254
题意:给以n*m的方格,方格中有1或者0,在1的地方可以放置一个物品,但是在物品的上下左右不能有不物品,也可以不放,问你最够有多少种放法。
题解:很简单的状态dp。这里先统计数最多能放多少个,然后和棋盘放k的kind那题一样,最后的结果就是第n行各种状态以及放置0到最多的种类之和。其实,这一题,个数那一维是完全可以删除的,只要2维就可以了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 char mp[13][13]; 7 int dp[13][900][160]; 8 const int N=(1<<14); 9 int n,m; 10 int total; 11 int s[N],ct[N],num; 12 int state[20]; 13 bool isok(int x){ 14 if(x&(x<<1))return false; 15 return true; 16 } 17 int counts(int x){ 18 int ans=0; 19 while(x){ 20 ans+=(x&1); 21 x/=2; 22 } 23 return ans; 24 } 25 void solve(){ 26 num=0; 27 for(int i=0;i<(1<<m);i++){ 28 if(isok(i)){ 29 ++num; 30 s[num]=i; 31 ct[num]=counts(i); 32 } 33 } 34 } 35 void sum(){ 36 total=0; 37 for(int i=1;i<=n;i++){ 38 for(int j=1;j<=m;j++){ 39 if(mp[i][j]=='1') 40 total++; 41 } 42 } 43 44 } 45 void input(){ 46 int cs=1,ans=0; 47 for(int i=1;i<=n;i++){ 48 cs=1,ans=0; 49 for(int j=m;j>=1;j--){ 50 if(mp[i][j]=='0'){ 51 ans+=cs; 52 } 53 cs*=2; 54 } 55 state[i]=ans; 56 } 57 } 58 int main(){ 59 while(~scanf("%d%d",&n,&m)){ 60 memset(dp,0,sizeof(dp)); 61 for(int i=1;i<=n;i++){ 62 for(int j=1;j<=m;j++) 63 cin>>mp[i][j]; 64 } 65 solve(); 66 sum(); 67 input(); 68 for(int i=1;i<=num;i++){ 69 if(state[1]&s[i])continue; 70 dp[1][i][0]=1; 71 } 72 for(int i=2;i<=n;i++){ 73 for(int j=1;j<=num;j++){ 74 if(state[i]&s[j])continue; 75 for(int k=ct[j];k<=total;k++){ 76 for(int g=1;g<=num;g++){ 77 if(state[i-1]&s[g])continue; 78 if(s[j]&s[g])continue; 79 dp[i][j][0]+=dp[i-1][g][0]; 80 dp[i][j][0]%=100000000; 81 } 82 } 83 } 84 85 } 86 long long as=0; 87 for(int i=1;i<=num;i++){ 88 for(int j=0;j<=total;j++){ 89 as+=dp[n][i][0]; 90 as%=100000000; 91 } 92 } 93 printf("%I64d\n",as%100000000); 94 } 95 }