您的位置:首页 > 其它

POJ 3254 Corn Fields(状压dp)

2013-07-05 14:41 381 查看
题目大意:有一个牧场,1代表可以放牧,0代表不可以放牧。而且不不可以带连续的牧场上同时放牧。

思路:状态压缩来表示放牧的状态。。。然后上代码。

过了一年从新写这道题。

去年什么都不会,就照着别人的版子抄。

思路分析:

状态方程:dp[i][state] 表示递推到第 i 行前面都不冲突的前提之下,第 i 行的状态为state的种数。

转移方程:dp[i][state] = segma( dp[i-1][s]) s的状态要和地图不冲突 , 也要和state 不冲突。

然后用位运算的技巧对地图判断冲突。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int mod = 100000000;
bool cando[1<<12];
int a[20];
int dp[20][1<<12];

int main()
{
    for(int s=0;s<(1<<12);s++)
    {
        cando[s]=true;
        for(int i=0;i<11;i++)
        {
            if(((1<<i)&s) && ((1<<i+1)&s))
                cando[s]=false;
        }
    }
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                int b;
                scanf("%d",&b);
                if(b)a[i]|=(1<<j);
            }
        }
        memset(dp,0,sizeof dp);
        for(int s=0;s<(1<<m);s++)
        {
            if(cando[s] && (s | a[0])==a[0])dp[0][s]=1;
        }

        for(int i=1;i<n;i++)
        {
            for(int last=0;last<(1<<m);last++)
            {
                if(cando[last] && (last | a[i-1])==a[i-1])
                {
                    for(int cur=0;cur<(1<<m);cur++)
                    {
                        if(cando[cur] && (cur | a[i])==a[i])
                        {
                            if((cur&last)==0)
                            {
                                dp[i][cur]=dp[i][cur]+dp[i-1][last];
                                dp[i][cur]%=mod;
                            }
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int s=0;s<(1<<m);s++)
        {
            if(cando[s])
            {
                ans+=dp[n-1][s];
                ans%=mod;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


这是13年的代码了。。。好怀旧- -

#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
const int mod = 100000000;
using namespace std;
int n,m;
int cur[20];   
int dp[20][1<<12];  //代表第一行到第I行的总和
vector <int> s;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        s.clear();
        memset(dp,0,sizeof(dp));
        memset(cur,0,sizeof(cur));
        int tmp=1<<m;
        for(int i=0;i<tmp;i++)
        if((i&(i<<1)) == 0)s.push_back(i);//这是每一行允许的放牧状态   奖i左移一位再与i取并  可以判断是否有连续的1  如果没有的话就加入允许状态里

        for(int i=1;i<=n;i++)
        {
            cur[i]=0;
            int num;
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&num);
                if(!num)cur[i]+=(1<<(m-j));   //对每一行取反  取反之后便可以判断是否合理放牧  
            }
        }

        for(int i=0;i<s.size();i++)//找出第一行可以放牧的状态  
        {
            if((s[i] & cur[1]) == 0)
            dp[1][i]=1;
        }

        for(int i=2;i<=n;i++)  //从第二行开始DP
        for(int j=0;j<s.size();j++)  //在第i行放入J状态   
        {
            if((s[j] & cur[i])==0)//判断J状态是否满足第一行的合理放牧
            {
                for(int k=0;k<s.size();k++)//在第i-1 行放入K状态  
                {
                    if((s[k] & cur[i-1])==0 && (s[k] & s[j])==0)//判断 第i-1行是否合理放牧  并判断与第i行是否有连续的放牧区域
                    dp[i][j]=(dp[i][j] + dp[i-1][k])%mod;//递推
                }
            }
        }
        int ans=0;
        for(int i=0;i<s.size();i++)
        ans=(ans + dp
[i])%mod;//找出第N行所有的状态之和

        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: