zoj 1100 鋪磚 狀態壓縮

1、st中存的是每一行擺放的所有可能,0是空着,1是佔着,st[i][0]中存一行的可能的狀態即from,st[i][1]中存與其匹配的下一行狀態即to;

2、dfs中from是一行中前n個格子的狀態,to是與之吻合的狀態;

3、因爲只看每一行的可能狀態,所以dfs中的n==w時已取完該種可能,退出遞歸;

4、對於一行的第n列,採取三種擺放長方形的方式

dfs(n+2,(from<<2)+3,(to<<2)+3); //橫着放,這層和下一層匹配的都多兩位1  (二進制11就是3嘛)
dfs(n+1,(from<<1)+1,to<<1);//豎着放,這層多一個1,匹配下層這個位置是0
dfs(n+1,from<<1,(to<<1)+1);//不放,這層多一個0,匹配的下層多個1

5、dp[i][j]中存第i行擺放狀態爲j時的方法數,邊界是要全放滿的,dp[0][(1<<w)-1]=1,最後要求的是dp[h][(1<<w)-1];

6、dp過程是

for(i=1;i<=h;i++)
{
        for(j=0;j<cnt;j++)
        {
               dp[i][st[j][1]]+=dp[i-1][st[j][0]];
       }

}

#include<stdio.h>
#include<string.h>
int st[3000][2];
int dp[11][3000]; //2^11=2048最多的狀態數
int cnt,h,w;
void dfs(int n,int from,int to)//枚舉所有一行擺放的可能和其匹配的下層
{
    if(n>w)
        return;
    if(n==w)  //這一行剛好擺完,得到一行擺放的組合
    {
        st[cnt][0]=from;
        st[cnt][1]=to;
        cnt++;
        return;
    }
    dfs(n+2,(from<<2)+3,(to<<2)+3); //橫着放,這層和下一層匹配的都多兩位1
    dfs(n+1,(from<<1)+1,to<<1);//豎着放,這層多一個1,匹配下層這個位置是0
    dfs(n+1,from<<1,(to<<1)+1);//不放,這層多一個0,匹配的下層多個1

}
int main()
{
    int i,j;
    while(scanf("%d %d",&h,&w)&&h)
    {
        if((w*h)%2)
        {
            printf("0\n");
            continue;
        }
        memset(dp,0,sizeof(dp));
        memset(st,0,sizeof(st));
        cnt=0; //記錄每一行擺放所有可能的狀態總數
        dfs(0,0,0);
        dp[0][(1<<w)-1]=1;//邊界
        for(i=1;i<=h;i++)
        {
            for(j=0;j<cnt;j++)
            {
                dp[i][st[j][1]]+=dp[i-1][st[j][0]];
            }
        }
        printf("%d\n",dp[h][(1<<w)-1]);
    }
    return 0;
}



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