zoukankan      html  css  js  c++  java
  • 【Luogu】P1879玉米田(状压DP)

    题目链接

    数据范围这么小,难度又这么大,一般就是状态压缩DP了。

    对输入进行处理,二进制表示每一行的草地状况。如111表示这一行草地肥沃,压缩成7.

    所以f[i][j]表示第i行状态为j时的方案数

    状态j指的是一个二进制集合,有牛在吃草的位置是1,不再吃草的位置是0

    f[i][j]=Sum(f[i-1][k])

    限制:(1) j必须是草地状况的子集。很好理解,如果有牛在贫瘠草地上吃草……会被投诉到动物保护协会的

    (2) j 的相邻两个位置不能都是1。 代码表示为!(j&(j<<1)

    (3) k 的上述两个限制。

    (4) k和j没有交集。这样可以保证没有相邻两个位置是1。 

    代码如下

    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<iostream>
    #define mod 100000000
    #define Max ((1<<m)-1)
    using namespace std;
    
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    int f[20][200000]={1};
    int s[20];
    
    int ans;
    int main(){
        int n=read(),m=read();
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j){
                int x=read();
                s[i]=(s[i]<<1)+x;
            }
        for(int i=1;i<=n;++i)
            for(int j=0;j<=Max;++j){
                if(((j|s[i])!=s[i])||(j&(j<<1)))    continue;
                for(int k=0;k<=Max;++k){
                    if(((k|s[i-1])!=s[i-1])||(k&(k<<1))||(k&j))    continue;
                    f[i][j]=(f[i][j]+f[i-1][k])%mod;
                }
            }
        for(int i=0;i<=Max;++i)
            ans=(ans+f[n][i])%mod;
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    两种存储思路
    越来越浅
    我了解的前端史
    关于称赞小孩
    怎么写递归
    Python笔记(十八):协程asyncio
    网络协议笔记(一):HTTP协议基础知识
    Linux笔记(三):常用命令
    算法笔记(九):二分查找
    数据结构笔记(二):栈、队列
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/7467434.html
Copyright © 2011-2022 走看看