N骑士问题 HDU4529

最近,郑厂长对八皇后问题很感兴趣,拿着国际象棋研究了好几天,终于研究透了。兴奋之余,坐在棋盘前的他又开始无聊了。无意间,他看见眼前的棋盘上只摆了八个皇后,感觉空荡荡的,恰好又发现身边还有几个骑士,于是,他想把这些骑士也摆到棋盘上去,当然棋盘上的一个位置只能放一个棋子。因为受八皇后问题的影响,他希望自己把这些骑士摆上去之后,也要满足每2个骑士之间不能相互攻击。
  现在郑厂长想知道共有多少种摆法,你能帮助他吗?

骑士的下法:
  每步棋先横走或直走一格,然后再往外斜走一格;或者先斜走一格,最后再往外横走或竖走一格(即走“日”字)。可以越子,没有”中国象棋”的”蹩马腿”限制。

一道简单的状态压缩dp,和皇后并没有什么关系,只是摆了皇后的地方不能摆骑士。

dp[i][num][j][k] 记录四个状态:
i 代表第 i 行
num 代表前i-1行里共有num个骑士
j 代表 i-1行的状态
k 代表 i 行的状态

转移方程 dp[i][cnt+num][k][l] += dp[i-1][num][j][k];
cnt 为当前行的骑士个数 l 代表第 i 行 ,k 代表 i - 1行,j代表 i - 2 行
直接暴力写肯定会跪,刚写出来本地运行一个用例要2秒多,加上一些简单的优化就搞定了。

#include
#include
#include

using namespace std;

int N;
int G[10];
int dp[10][11][1<<8][1<<8];
 //行数(从第二行开始) 前i行骑士个数
 //i-2行状态 i-1行状态

int lowbit(int k)
{
    return k&(-k);
}

int cal(int n)
{
    int res = 0;
    while(n)
    {
        res++;
        n -= lowbit(n);
    }
    return res;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(G,0,sizeof(G));
        memset(dp,0,sizeof(dp));
        scanf("%d",&N);
        for(int i=2;i<=9;i++)
        {
            getchar();
            for(int j=0;j<8;j++)
            {
                char c;
                scanf("%c",&c);
                if(c == '*') G[i] |= 1 << j;
            }
        }
        dp[1][0][0][0] = 1;
        int res = 0;
        int tot = 1 << 8;
        for(int i=2;i<=9;i++)
            for(int j=0;j// 前两行
                if(G[i-2] & j) continue;
                for(int k=0;k//前一行
                    if(G[i-1] & k) continue;
                    for(int l=0;lif(G[i] & l) continue;
                        int jj = 0; //前两行对本行的影响
                        jj |= j << 1;
                        jj |= j >> 1;
                        jj &= tot - 1;
                        int kk = 0; //前一行对本行的影响
                        kk |= k << 2;
                        kk |= k >> 2;
                        kk &= tot - 1;
                        if((jj|kk) & l) continue;
                        int cnt = cal(l);
                        for(int num=0;num+cnt<=N;num++)
                        {
                            dp[i][cnt+num][k][l] += dp[i-1][num][j][k];
                            if(i == 9 && cnt + num == N) res += dp[i-1][num][j][k];
                        }
                    }
                }
            }
        printf("%d\n",res);
    }
    return 0;
}

你可能感兴趣的:(dp,hdu)