POJ

来源:互联网 发布:北京值得去的地方知乎 编辑:程序博客网 时间:2024/06/18 16:44

题意

农夫在一块M*N的农田上种庄稼,其中有些能种,有些不能种,且要求所种庄稼不能相邻,现求种田方案数.
1<=M,N<=12.
input
2 3
1 1 1
0 1 0
output
9

题解1(状压DP)

分析

每一行的状态都可以用一个整数来描述.所以有:

dp[i][j]: 前面i+1行, 且第i行的状态为j 的方案数.

首先初始化dp数组为全0, 然后先判断第0行的1<< n个状态, 假如该状态对应的田地都是可种植的, 且均不相邻, 则置为1.
接着逐步从第1行推到第m-1行, 每行的转移要枚举1<< n个状态, 具体的转移过程如下:
首先, 第i行第j个状态要合法(该状态对应的田地都是可种植的, 且均不相邻), 其次, 枚举上一行的1<< n个状态, 用k表示, 假如k&j==0, 那么就说明可以由k状态转移到j状态, 否则不行.

代码

#include<set>#include<map>#include<ctime>     //CLOCKS_PER_SEC;clock_t t=clock();#include<cmath>     #include<queue>#include<bitset>#include<cctype>#include<cstdio>#include<vector>#include<string>    //getline(cin, line);#include<sstream>   //stringstream ss(line);(ss is a stream like cin).#include<cstdlib>#include<cstring>#include<float.h>   //X=FLT,DBL,LDBL;X_MANT_DIG,X_DIG,X_MIN_10_EXP,X_MIN_10_EXP,X_MIN,X_MAX,X_EPSILON#include<limits.h>  //INT_MAX,LLONG_MAX#include<iostream>  //ios_base::sync_with_stdio(false);#include<algorithm>using namespace std;typedef long long ll;typedef vector<int> vi;typedef pair<int,int> pii;const double PI = acos(-1.0);const int INF=0x3f3f3f3f;const int Max=1;const int mod=100000000;int dp[19][1<<13], d[19][19], n, m;bool check(int row, int status){    for(int i=0; i<m; i++)        if(d[row][i]==0 && status&(1<<i))            return false;    return true;}int main(void){    //freopen("in", "r", stdin); freopen("out", "w", stdout);    while(~scanf("%d%d", &n, &m)){        for(int i=0; i<n; i++)            for(int j=0; j<m; j++)                scanf("%d", &d[i][j]);        memset(dp, 0, sizeof dp);        int r=1<<m;        for(int i=0; i<r; i++)            if(check(0, i)&&!(i&i<<1))                dp[0][i]=1;        for(int i=1; i<n; i++){            for(int j=0; j<r; j++){                if(!(j&j<<1) && check(i, j)){                    for(int k=0; k<r; k++){                        if(!(k&j))                            dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;                    }                }            }        }        int ans=0;        for(int i=0; i<r; i++)            ans=(ans+dp[n-1][i])%mod;        printf("%d\n", ans);    }    return 0;}

题解2(dfs)

分析

假如n, m不那么大的话, 还可以用dfs写.

代码

//dfs, TLE.#include<set>#include<map>#include<cmath>#include<queue>#include<cctype>#include<cstdio>#include<vector>#include<string>#include<sstream>#include<cstdlib>#include<cstring>#include<float.h>   //X=FLT,DBL,LDBL;X_MANT_DIG,X_DIG,X_MIN_10_EXP,X_MIN_10_EXP,X_MIN,X_MAX,X_EPSILON#include<limits.h>  //INT_MAX,LLONG_MAX#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const double PI = acos(-1.0);#define INF 0x3f3f3f3fint ans=0,n,d[19][19],vis[19][19],m;void dfs(int row, int col, int cnt){    if(cnt==0){        ans=(ans+1)%100000000;        return;    }    if(row>=m)        return;    if(col>=n){        dfs(row+1, 0, cnt);        return;    }    if(d[row][col]==1 && (row-1<0||vis[row-1][col]==0) && (col-1<0||vis[row][col-1]==0)){        vis[row][col]=1;        dfs(row, col+1, cnt-1);        vis[row][col]=0;    }    dfs(row, col+1, cnt);}int main(void){    //freopen("in", "r", stdin); freopen("out1", "w", stdout);    while(~scanf("%d%d", &m, &n)){        int legal=0;        for(int i=0; i<m; i++){            getchar();            for(int j=0; j<n; j++){                scanf("%d", &d[i][j]);                if(d[i][j]) legal++;            }        }        ans=0;        for(int i=0; i<=legal; i++){            memset(vis, 0, sizeof vis);            dfs(0, 0, i);        }        printf("%d\n", ans);    }    return 0;}
0 0
原创粉丝点击