狀壓dp

完全不會
先抄一遍代碼感受一下
1087: [SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 3860 Solved: 2261
[Submit][Status][Discuss]
Description

  在N×N的棋盤裏面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上
左下右上右下八個方向上附近的各一個格子,共8個格子。
Input

  只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output

  方案數。
Sample Input
3 2
Sample Output
16
據說很水啊
不過我連八皇后還是最近纔會的

#include<bits/stdc++.h>
using namespace std;
int n,m,all,cnt[512];
long long f[10][100][512];
bool c1[512],c2[512][512];
long long ans;
void pre()
{
    int s;//猜測目的應該是要去掉一些顯然不成立的情況
    //例如兩個國王在一起之類的 
    for(int i=0;i<=all;i++)
        if((i&(i>>1))==0)
        {
            s=0;
            for(int x=i;x;x>>=1) s+=(x&1);
            //判斷國王的個數 
            cnt[i]=s;

            c1[i]=1;//定義這個情況是合理的 

        }
        for(int i=0;i<=all;i++)if(c1[i])
            for(int j=0;j<=all;j++) if(c1[j])
                if(((i&j)==0)&&((i&(j>>1))==0)&&((j&(i>>1))==0))
                    c2[i][j]=1;
                    //判斷兩種情況是否能和並
                    //首先兩種情況都需要合法,如果兩列不在同一個位置有點,且左右移也沒有
                    //那麼這兩種情況就可以放在一起 
}

int main()
{
    scanf("%d%d",&n,&m);
    all=(1<<n)-1;//一串長度爲n的1 
    pre(); 
    for(int i=0;i<=all;i++) if(c1[i]) f[1][cnt[i]][i]=1;//對於每種單個的情況 計數 
    for(int j=1;j<n;j++)//對於多個的情況計數 
        for(int k=0;k<=all;k++) if(c1[k])
            for(int i=0;i<=all;i++)if(c1[i])
                if(c2[k][i])
                    for(int p=cnt[k];p+cnt[i]<=m;p++)
                        f[j+1][p+cnt[i]][i]+=f[j][p][k];
                        //之後只要兩行各自合法且合併合法就轉移

    long long ans=0;

    for(int i=0;i<=all;i++) ans+=f[n][m][i];//將符合要求的情況加起來 
    printf("%lld",ans);
    return 0;
}

仔細標上註釋發現其實蠻簡單的
代碼是抄的黃學長的。

所以可能需要強迫自己去跟着過程走一遍
注意要按程序運行順序

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