FZU 1025 状压dp 摆砖块

云峰菌曾经提到过的黄老师过去讲课时的摆砖块 那时百度了一下题目 想了想并没有想好怎么dp 就扔了

这两天想补动态规划知识 就去FZU做专题 然后又碰到了 就认真的想并且去做了

dp思想都在代码注释里

思想是很好想的..唯一的难点大概是 c++里面没有同或这种东西 得自己写

而我又不怎么会位运算 问了蕾姐半天也没搞懂怎么用~这个取反符号

到最后怒而手写了函数

一开始想的是 init后 输入nm都可以秒出 但是在使用~的路途上 发现至少我的方法 做这个题 不能做到init后随便输入

因为 每行 都有(1<<m)-1个砖块需要去放 而我又采用的是上下都是0 我默认去放一个竖着的砖块 这样 我dp的时候 对每种m 都要设置边界 因为上一行和这一行的砖块 我枚举出来的数字的二进制都未必有m位 如果仅仅按照~来看 如果忽略符号位什么的 也是不对的 因为后面的那些0 被忽视了

所以每个数 如果枚举不到m位 我就把它当作m位 这个设置 在qf(int x,int len)里面

由于我需要输入m后再进行init 那么时间复杂度当然会比较高 limit:1000ms time:656ms 回头我再去看别人的直接算的办法

题目的错点 long long dp %I64d

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<iostream>
using namespace std;
/// 状压dp 传说中黄老师讲的摆砖块
long long int dp[15][1<<12];
/// dp[i][k] i x k 状态
int n,m;
int qf(int x , int len)
{
    int w=0;
    int A[15];
    memset(A,0,sizeof(A));
    while(x>0)
    {
        w++;
        A[w]=x%2;
        x/=2;
    }
    int res=0;
    for(int i=1; i<=len; i++)
    {
        int q=1;
        if(A[i]==1)
            continue;
        for(int l=1; l<i; l++)
        {
            q*=2;
        }
        res+=q;
    }
    return res;
}
int l(int a,int b,int len)
{
    return ((qf(a,len)&qf(b,len)));
}
/// 放置 1 未放置 0
/// 每次放置都进行判断
/**
枚举 : 只枚举横向放置的砖块 砖块的可行性为judge函数
1 枚举每种状态 与上一行的进行比较 如果上1下1 可以 上1下0 可以 上0下1 不可以 上0上0 全部改为1
2 对每种上0下0的状态进行改变 即 即 使其加上 ((~a)&(~b)) 得到同或后的值
3 对这种改变之后的dp数组进行改变
4 最后输出的是dp[n][(1<<m)-1]

上a 下b 的判断
(a^b)&b!=0 continue;
**/
bool judge(int x)
{
    int A[15];
    int w=0;
    int z;
    z=x;
    while(z)
    {
        w++;
        A[w]=z%2;
        z/=2;
    }
    for(int i=1; i<=w; i++)
    {
        if(A[i]==1)
        {
            if(i+1>w||A[i+1]!=1)
                return false;
            i++;
        }
    }
    return true;
}
int len;
int sz[2000];
void ok()
{
    for(int i=0; i<=(1<<m)-1; i++)
    {
        if(judge(i))
        {
            len++;
            sz[len]=i;
        }
    }
}
void init()
{
    len=0;
    ok();
    memset(dp,0,sizeof(dp));
    for(int k=0; k<=(1<<m)-1; k++)
    {
        if(judge(k))
        {
            dp[1][k]=1;
        }
    }
    for(int i=2; i<=n; i++)
    {
        for(int j=1; j<=len; j++)
        {
            for(int k=0; k<=(1<<m)-1; k++)
            {
                int a=k;
                int b=sz[j];
                if(((a^b)&b)!=0)
                    continue;
                b+=l(a,b,m);
                dp[i][b]+=dp[i-1][k];

            }
        }
    }
}
int main()
{
    while(cin>>n>>m)
    {
        if(n==0&&m==0)
            break;
        init();
        printf("%I64d\n",dp[n][(1<<m)-1]);
    }
}

  

时间: 2024-10-02 00:26:11

FZU 1025 状压dp 摆砖块的相关文章

状压DP入门——铺砖块

题目描述 现有n*m的一块地板,需要用1*2的砖块去铺满,中间不能留有空隙.问这样方案有多少种 输入 输入n,m(1<=n, m<=11) 有多组输入数据,以m=n=0结束 输出 输出铺砖块的方案数 样例输入 1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0 样例输出 1 0 1 2 3 5 144 51205 我A的第一道状压DP题是导游,感觉就是背包~~ 此题不是很懂 此题状压DP,DP[i][sta]表示前i行填满对第i+1行的影响为状态sta时的方案总数 易知

【HDU3341】 Lost&#39;s revenge (AC自动机+状压DP)

Lost's revenge Time Limit: 5000MS Memory Limit: 65535KB 64bit IO Format: %I64d & %I64u Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is t

fzu2188 状压dp

G - Simple String Problem Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice FZU 2218 Description Recently, you have found your interest in string theory. Here is an interesting question about strings.

【POJ 2411】Mondriaan&#39;s Dream(状压dp)

[POJ 2411]Mondriaan's Dream(状压dp) Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 14107   Accepted: 8152 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in hi

刷题向》关于第一篇状压DP BZOJ1087 (EASY+)

这是本蒟蒻做的第一篇状压DP,有纪念意义. 这道题题目对状压DP十分友善,算是一道模板题. 分析题目,我们发现可以用0和1代表每一个格子的国王情况, 题目所说国王不能相邻放置,那么首先对于每一行是否合法的判断条件就出来了:就是对于情况X,如果X&(x<<1)==0,即为合法情况. 同理这样我们就可以得出每一行对于上一行是否合法的条件:(x&y)==0&&(x&(y<<1))==0&&(x&(y>>1))==

【状压dp】互不侵犯KING

互不侵犯KING Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3866  Solved: 2264[Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Outp

HDU 3341 Lost&#39;s revenge(AC自动机+状压DP)

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 4548    Accepted Submission(s): 1274 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

Mondriaan&#39;s Dream【状压DP】

测评传送门 题意: 给定一个 n*m 的矩形,用1*2的方块填充的所有方案数 Sample Input 1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0 Sample Output 1 0 1 2 3 5 144 51205 思路: 像这样看上去就不会做的题目数据范围一般都不大(因为要用状压呀,大了能存的下吗?) 而且显然答案会很大,所以记得开 long long 正题---- 我们可以一行一行地看,对于上一行地情况,可以是横着的也可以是竖着的,横着的对我们当前这一行的

[JZOJ5398]:Adore(状压DP+记忆化搜索)

题目描述 小$w$偶然间见到了一个$DAG$. 这个$DAG$有$m$层,第一层只有一个源点,最后一层只有一个汇点,剩下的每一层都有$k$个节点. 现在小$w$每次可以取反第$i(1<i<n-1)$层和第$i+1$层之间的连边.也就是把原本从$(i,k_1)$连到$(i+1,k_2)$的边,变成从$(i,k_2)$连到$(i+1,k_1)$. 请问他有多少种取反的方案,把从源点到汇点的路径数变成偶数条? 答案对$998244353$取模. 输入格式 一行两个整数$m,k$. 接下来$m-1$行