hdu1693 Eat the Trees 插頭DP

題目:點擊打開鏈接

題意:一個棋盤上有0,1.需要找一些迴路把1全部串起來,問總方法數

分析:插頭dp第一題,果然有點難度,用了我一天的時間,還是自己太菜了。。。。

我是看了這個圖才恍然大悟的,這就對應下面的三種可以聯通的情況。

對於爲什麼 f[i][0][s<<1]=f[i-1][m][s];我搜的題解都沒有說,因爲這個很難描述,這裏只簡單的說一下,然後自己畫個圖慢慢體會吧。因爲第i-1行最後一格的右輪廓線一定沒有右插頭,而第i行第0格(其實不存在,只是爲了用來轉移狀態)的右插頭也一定不存在,而其餘輪廓段的狀態都是一樣的,所以f[i][0][s<<1]=f[i-1][m][s],s<<1是因爲要得到第i行第0格的狀態,只需要把第i-1行最後一格的狀態右移一位就好了,(把右邊的0抹去了,左邊新加了一個0).不說了,再說就亂了,總之,結合代碼,再結合圖片,一步步推一下把。

可參考文檔:

http://www.docin.com/p-741918386.html



https://img-blog.csdn.net/20150518123601141?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY29ybmNzZA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

圖片來自:點擊打開鏈接


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=13;
int a[N][N];
ll f[N][N][1<<N]; //初始化的時候<<弄成了>>,結果找了半天bug總是找不到哪裏錯了,最後發現是這裏。。。。
int main()
{
    int T;
    //freopen("f.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&a[i][j]);
            }
        }
        f[0][m][0]=1;
        int full=1<<m;
        for(int i=1;i<=n;i++){
            for(int s=0;s<full;s++) 
                f[i][0][s<<1]=f[i-1][m][s];
            for(int j=1;j<=m;j++){
                int r=1<<j;//第j個格子的右輪廓段
                int d=1<<(j-1); //第j個格子的下輪廓段
                for(int s=0;s<(full<<1);s++){
                    bool x=s&r; //右端輪廓段是否有插頭
                    bool y=s&d; //下端輪廓段是否有插頭
                    if(a[i][j]){
                        if(x&&!y||y&&!x) //如果只有一個插頭,那麼就有兩條路來的,如上圖第二個
                            f[i][j][s]=f[i][j-1][s^r^d]+f[i][j-1][s];
                        else  //如果已經有了兩個插頭或者沒有插頭,那麼只有一條路來的,如上圖一三個分別對應這兩種情況
                            f[i][j][s]=f[i][j-1][s^r^d];
                    }
                    else{
                        if(!x&&!y)
                            f[i][j][s]=f[i][j-1][s];
                        else f[i][j][s]=0;
                    }
                }
            }
        }
        printf("Case %d: There are %I64d ways to eat the trees.\n",cas,f[n][m][0]);

    }
    return 0;
}


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