轮廓线DP POJ3254

补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点:

5 6 7 8 9

1 2 3 4

如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了。注意多记录些信息对简化代码是很有帮助的,尤其对于我这种代码经常错的一塌糊涂的人来说。。

呆马:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#define inf 1000000007
#define oo 100000000
#define maxn 15
#define maxm 5200

using namespace std;

int n,m,mb;
int a[maxn][maxn];
int f[maxn][maxn][5000];
int bit[5000][maxn];

bool legal(int x, int y,int mask)
{
    if (y==1) if (bit[mask][y]&bit[mask][y+1]) return 0;
    for (int i=1;i<y-1;i++) if (bit[mask][i]&bit[mask][i+1]) return 0;
    for (int i=y;i<m;i++) if (bit[mask][i]&bit[mask][i+1]) return 0;
    return 1;
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(a,0,sizeof(a));
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    mb=(1<<m)-1;
    for (int mask=0;mask<=mb;mask++)
    {
        int tmp=mask;
        for (int i=1;i<=m;i++)
        {
            bit[mask][i]=tmp%2;
            tmp/=2;
        }
    }
    memset(f,0,sizeof(f));
    f[0][m][0]=1;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            for (int mask=0;mask<=mb;mask++)
                if (legal(i,j,mask))
                {
                    int tmp=1<<(j-1);
                    if (j==1)
                    {
                        f[i][j][mask&(~tmp)]+=f[i-1][m][mask];
                        f[i][j][mask&(~tmp)]%=oo;
                        if (!bit[mask][j] && a[i][j])
                        {
                            f[i][j][mask|tmp]+=f[i-1][m][mask];
                            f[i][j][mask|tmp]%=oo;
                        }
                    }
                    else
                    {
                        f[i][j][mask&(~tmp)]+=f[i][j-1][mask];
                        f[i][j][mask&(~tmp)]%=oo;
                        if (!bit[mask][j] && a[i][j])
                        {
                            f[i][j][mask|tmp]+=f[i][j-1][mask];
                            f[i][j][mask|tmp]%=oo;
                        }
                    }
                }
    int ans=0;
    for (int mask=0;mask<=mb;mask++)
        if (legal(n+1,1,mask))
        {
            ans+=f[n][m][mask];
            ans%=oo;
        }
    printf("%d\n",ans);
    return 0;
}

Corn Fields

时间: 2024-10-05 04:26:05

轮廓线DP POJ3254的相关文章

POJ 3254 Corn Fields (状压DP,轮廓线DP)

题意: 有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)? 思路: 明显的状压DP啦,只是怎样压缩状态?跟轮廓线DP一样,按格子为单位来设计状态,一个状态只需要表示到其上方和左方的格子,所以最多只需要保存min(n,m)个01状态就行了(可以尝试旋转一下矩阵),最多需要12位.用哈希表来做会比较快吧,不用去考虑无效的状态,比如出现相邻两个1. 1 //#include <bits/stdc++.

轮廓线dp (插头dp)

轮廓线dp 骨牌覆盖问题 n和m比较小 1 #pragma comment(linker, "/STACK:102400000,102400000") 2 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 #include <iostream> 9 #includ

POJ 2411 Mondriaan&#39;s Dream( 轮廓线dp )

最普通的轮廓线dp... 复杂度O(nm2min(n, m)) -------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; #define b(x) (1 << (x)) const in

hdu 5766 Filling 轮廓线dp burnside

Filling 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5766 Description The board is a rectangle of unit cells with N rows and N columns. At first, cells are empty. ?? has infinite blocks with the size of 2*2. ?? can put blocks in the board as long

UVa 11270 铺放骨牌(轮廓线DP)

https://vjudge.net/problem/UVA-11270 题意: 用1×2骨牌覆盖n×m棋牌,有多少种方法? 思路: 这道题目是典型的轮廓线DP题. 所谓轮廓线DP,就是以整行整列为状态进行动态规划时无法进行状态转移,那么此时就可以用到轮廓线,当然,这种方法只能使用在一个窄棋盘上,大了肯定是不行的,要超时! ' 轮廓线DP就是按照从上到下,从左到右的顺序进行状态转移,每个格子用二进制来表示状态,1代表的就是覆盖,0代表未覆盖. 以本题为例,如上图,我们现在要计算 k 格子,那么与

HDU4949 Light (轮廓线dp)

题意:给你一个01矩阵,有两种操作: 第一种: 把a(i,j)的周围四个都异或一下 第二种: 把a(i, j)的周围四个和a(i,j)都异或一下 求把矩阵变成全0矩阵的最少操作次数 思路:如下图所示的轮廓线dp,逐格递推的,cur为当前决策的格子,红色线就是轮廓线,轮廓线以上的格子的操作状态都已经确定了,而对下面状态有影响的只有黄色格子,每个格子保存的是格子当前的数和它自己操作了多少次,因为无论是1还是2操作,对其他格子的影响都是一样的,这样子的复杂度是O(n*m*4^10),明显是会超时的.然

poj 2411 Mondriaan&#39;s Dream (轮廓线DP)

题意:有一个n*m的棋盘,要求用1*2的骨牌来覆盖满它,有多少种方案?(n<12,m<12) 思路: 由于n和m都比较小,可以用轮廓线,就是维护最后边所需要的几个状态,然后进行DP.这里需要维护的状态数就是min(n,m).即大概是一行的大小.每次放的时候,只考虑(1)以当前格子为右方,进行横放:(2)以当前格子为下方进行竖放:(3)还有就是可以不放. 3种都是不一样的,所以前面的一种状态可能可以转为后面的几种状态,只要满足了条件.条件是,横放时,当前格子不能是最左边的:竖放时,当前格子不能是

【轮廓线DP】POJ2411-Mondriaan&#39;s Dream

今天美国的院士过来讲课XD以为会很无聊但是谜之好听,而且英语基本上都听懂了的样子?(´▽`) 逃到图书馆来写解题报告 [题目大意] 给出一个m*n的方格,用2*1的骨牌覆盖有几种情况. [思路] 最基础的轮廓线DP.分为三种情况: (1)向上放,必须要满足上面的格子没有被放,且当前不在首行.→新状态=旧状态删去首位,末尾为1: (2)向左放,必须要满足左边的格子和上面的格子都没有放,且当前不在首列.→新状态=旧状态删去首位,末两位微1: (3)不放,必须满足上面的格子没有放.新状态=旧状态删去首

hdu 4804 Campus Design 轮廓线dp

题意: 给出一个n*m的01矩阵,其中要求把矩阵里面的1用1*1或1*2的砖块铺满,矩阵里面的0为障碍物,问使用1*1的砖块数>=c && <=d 的方案有多少种. 限制: 1 <= n <= 100; 1 <= m <= 10; 1 <= c <= d <= 20; 思路: 因为 1 <= m <= 10 所以可以采用轮廓线dp, 具体状态解释在代码中说明. /*hdu 4804 Campus Design 轮廓线dp 题