poj2411(상압dp)

1812 단어 dppoj
이 문제는 문제풀이를 보지 않고 전혀 생각이 없다.
아이디어는 다음과 같습니다.
직사각형에는 가로놓기, 세로놓기, 놓지 않는 세 가지 방법이 있다.i행은 i-1행의 방치와만 관계가 있기 때문에 우리는 i-1행사가 가득 차도록 보장해야 하기 때문에 현재 dp[i][state]로 i행을 표시합니다
상태가state인 경우 dp[i][now]=sum{dp[i-1][pre]}.
가로놓다
만약에 i행의 d열에서 우리가 가로로 놓기를 선택한다면 i행의 d열과 d+1열은 모두 1이고 i-1행의 d열과 d+1열도 반드시 1(꽉 차게 보장)이어야 하며 상태가 다음과 같이 옮겨야 한다.
d=d+2,now=now<<2|3,pre=pre<<2|3.
세로
i행의 d열에서 우리는 세로로 놓기를 선택한다. 그러면 i행의 d열은 1이고 i-1행의 d열은 0이어야 한다. (우리는 세로로 놓았기 때문에 앞줄이 비어 있지 않으면 어떻게 내려놓을 수 있습니까) 상태 이동:
d=d+1,now=now<<1|1,pre=pre<<1.
괜찮다
i행의 d열은 무방하다. 그러면 i-1행의 d열은 틀림없이 1이다. (꽉 차게 보장), 상태 이동:
d=d+1,now=now<<1,pre=pre<<1|1.
이 문제는 진심으로 이해하지 못한다는 것을 점차적으로 나타내기 때문에 기억을 최적화하여 검색해 보자.
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef __int64 lld;
#define oo 0x3f3f3f3f
#define Mod 1000000007
#define maxn (1<<11)+1
lld dp[maxn][12];
int n,m;

void dfs(int r,int c,int now,int pre)
{
    if(c==m)
    {
        dp[now][r]+=dp[pre][r-1];
        return ;
    }
    //  
    dfs(r,c+1,now<<1|1,pre<<1);
    //  
    if(c+2<=m)
        dfs(r,c+2,now<<2|3,pre<<2|3);
    //  
    dfs(r,c+1,now<<1,pre<<1|1);
}

int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        if(n*m&1)
        {
            puts("0");
            continue;
        }
        int all=(1<<m)-1;
        memset(dp,0,sizeof dp);
        dp[all][0]=1;//0       
        for(int i=1;i<=n;i++)
            dfs(i,0,0,0);
        printf("%I64d
",dp[all][n]);// } return 0; }

좋은 웹페이지 즐겨찾기