SGU 131(狀壓壓縮+dp)

// 題意:一個n*m的矩陣,求用I型(1 * 2)和L型的兩種方塊進行填滿有多少種方法
// 方法:這題和poj2411有點類似 做過方塊填充的應該都認得出來要用狀壓
// 但是要比poj2411複雜 思路也是類似 不過因爲要考慮L型 情況也複雜的多
// 語文有點不太好  可能有點說不清楚
// 利用兩個參數 b1 表示前面的放置方式對now(當前行狀態)的當前列的影響,b2 表示對pre(上一行狀態)的當前列的影響
// 有影響爲1 沒影響爲0 其實可以這麼理解 如果爲1就代表有方塊從左邊凸出來會佔用當前列 爲0就代表沒有凸出來
// 這裏我提出一些自己遇到的問題
// 首先枚舉當前狀態和上一狀態要分成兩種情況考慮
// 不僅要考慮b1,b2 還要考慮從下往下凸出來的這種情況,就是上一行的上一行有方塊凸下來佔用上一行 說起來有點繞
// 舉個例子 如果當前  b1 == 0 && b2 == 0
// 那麼這一列我們可以這麼放
//   1         1 1        1          1  1
//      或者         或者        或者        (這四種是上一行的上一行沒有從上往下凸出來的方塊的放置方法)
//   1         1          1  1          1

//      1
//         或者         或者   不放  (這三種是上一行的上一行有從上往下凸出來的方塊的放置方法)
//   1  1        1  1
// 上面總共7種  上面的每種都滿足把上一行的當前列填滿了 只不過是分爲是由左邊凸出來的 和 上面凸出來的
// 填滿我起初也有疑問爲什麼下面的這三种放置也可以
// 語文果然不太好  看下面幾張圖一定有用



#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

int n, m;
long long ans[10][10];
long long dp[10][1<<10];

// 一    二    三    四     五    六
// 1    1 1   1       1   1 1
// 1    1     1 1   1 1     1   1 1

void dfs(int line, int k, int now, int pre, int b1, int b2)
{
    if(k == m){
        if(!b1 && !b2) dp[line][now] += dp[line - 1][pre];
        return;
    }
    if(!b1 && !b2){
        dfs(line, k + 1, now<<1|1,  pre<<1,   0, 0); // 第一種方法放置
        dfs(line, k + 1, now<<1|1,  pre<<1,   1, 0); // 第二種方法放置
        dfs(line, k + 1, now<<1|1,  pre<<1,   0, 1); // 第三種方法放置
        
        dfs(line, k + 1, now<<1|b1, pre<<1,   1, 1); // 第五種方法放置
        
        dfs(line, k + 1, now<<1|1,  pre<<1|1, 1, 1); // pre當前位的1是從上向下凸出來的  第四種方法放置
        dfs(line, k + 1, now<<1|1,  pre<<1|1, 1, 0); // pre當前位的1是從上向下凸出來的  第六種方法放置
        
        dfs(line, k + 1, now<<1|0,  pre<<1|1, 0, 0); // 當前位置不放
    }
    else if( b1 && !b2)
    {
        dfs(line, k + 1, now<<1|1,  pre<<1,   1, 1); // 第五種方法放置
        dfs(line, k + 1, now<<1|1,  pre<<1|1, 0, 0); // pre當前位的1是從上向下凸出來的
    }
    else if(!b1 && b2)
    {
        dfs(line, k + 1, now<<1|1,  pre<<1,   1, 1); // 第四種方法放置
        dfs(line, k + 1, now<<1|1,  pre<<1,   1, 0); // 第六種方法放置
        dfs(line, k + 1, now<<1,    pre<<1,   0, 0); // 當前位置不放
    }
    else{
        dfs(line, k + 1, now<<1|1,  pre<<1,   0, 0); // 因爲b1和b2都爲1 所以直接跳到下一行
    }
}

int main()
{
    memset(ans, 0, sizeof ans);
    memset(dp, 0, sizeof dp);
    while(cin>>n>>m)
    {
        if(ans[n][m]){
            cout<<ans<<endl;
            continue;
        }
        if(n < m)
            swap(n, m);
        dp[0][(1<<m) - 1] = 1;
        for(int i = 1; i <= n; i++)
            dfs(i, 0, 0, 0, 0, 0);
        ans[n][m] = ans[m][n] = dp[n][(1<<m) - 1];
        cout<<ans[n][m]<<endl;
        
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章