HDOJ 1693

題意:給定N*M的矩陣,裏面有些有樹,有些沒樹(用0表示),問有多少種方法,通過任意個不交叉環路把樹全連起來(就是哈密頓迴路或者多個哈密頓迴路覆蓋所有非0數)

題解:插頭DP入門題,實際上,感覺插頭DP也就是狀態壓縮DP的一種特例而已。若要學插頭DP,請參見《基於連通性狀態壓縮的動態規劃問題》,看了它,也就知道一些基本概念和解題思路了。

這道題我的方法是dp[i][j][st]代表第i行格子,進行到第j個豎線(該格子左方),輪廓線插頭狀態爲st時的狀態數(1代表有插頭,0代表沒插頭)。

當map[i][j+1]爲0時,看st對應的兩個插頭是否爲1,因爲不能經過(i,j+1)這個格子,所以有插頭的狀態均淘汰掉,可行狀態則直接轉移,dp[i][j+1][st]+=dp[i][j][st]

當map[i][j+1]不爲0時,看st的兩個插頭:

1、都是1,這個格子的插頭狀況也就唯一確定了,直接推出dp[i][j+1][st-a-b]+=dp[i][j][st];(a,b爲相關插頭的二進制編碼)

2、都是0,由於迴路經過的格子必有兩個插頭,這個格子的插頭也就確定了,dp[i][j+1][st|a|b]+=dp[i][j][st];

3、只有一個1,那麼轉移就有兩種可能,向左或者向下,即dp[i][j+1][(st&(~a))|b]+=dp[i][j][st];dp[i][j+1][(st&(~b))|a]+=dp[i][j][st];

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int map[13][13],n,m;
LL dp[13][13][(1<<13)+1];
int main()
{
    int T,ca=0;
    for(scanf("%d",&T);T;T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&map[i][j]);
        memset(dp,0,sizeof(dp));
        dp[0][m][0]=1;
        int tot=1<<(m+1),haf=1<<m;
        for(int i=1;i<=n;i++)
        {
            for(int tp=0;tp<haf;tp++)
               dp[i][0][tp]=dp[i-1][m][tp<<1];
            for(int j=0;j<m;j++)
            {
                for(int st=0;st<tot;st++)
                {
                    if(!dp[i][j][st])
                        continue;
                    int x=i,y=j+1,a=1<<(m-y),b=1<<(m-y+1);
                    if(map[x][y]==0)
                    {
                        if((st&a)||(st&b))
                            continue;
                        dp[i][j+1][st]+=dp[i][j][st];
                    }
                    else if((a&st)||(b&st))
                    {
                        if((a&st)&&(b&st))
                            dp[i][j+1][st-a-b]+=dp[i][j][st];
                        else
                        {
                            dp[i][j+1][(st&(~a))|b]+=dp[i][j][st];
                            dp[i][j+1][(st&(~b))|a]+=dp[i][j][st];
                        }
                    }
                    else
                    {
                        dp[i][j+1][st|a|b]+=dp[i][j][st];
                    }
                }
            }
        }
        printf("Case %d: There are %I64d ways to eat the trees.\n",++ca,dp[n][m][0]);
    }
    return 0;
}


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