hdu4529郑厂长系列故事——N骑士问题

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <queue>

using namespace std;

const int ROW = 9;
const int COL = 8;
const int KNIGHT = 10 + 1;     //其实上限
const int STATE = (1 << 8);    //状态上限
int cases, m, cur[ROW];
long long dp[2][KNIGHT][STATE][STATE], ans, cu, ne;
int results[STATE];    //储存每个状态的骑士数目
bool exista[STATE][STATE], existb[STATE][STATE];    //相邻两行是否能共存,相间两行是否能共存.
char mt[ROW][COL];    //储存map

template <class T>
bool read(T &n)
{
    T x = 0, temp = 1;
    char c;
    while (((c = getchar()) < '0' || c > '9') && c != EOF && c != '-');
    if (c == EOF) return false;
    if (c == '-') temp = -1, c = getchar();
    x = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
    n = temp * x;
    return true;
}

bool yes(int state, int i)   //是否与皇后冲突
{
    if (i < 0) return false;
    return !(state & cur[i]);
}

bool okone(int i, int j)    //相邻两行是否冲突
{
    return !((i & (j << 2)) || (i & (j >> 2)));
}

bool okanother(int i, int j)    //相间两行是否冲突
{
    return !((i & (j << 1)) || (i & (j >> 1)));
}

void init()
{
    for (int i = 0; i < STATE; i++)
    {
        for (int j = 0; j < STATE; j++)
        {
            if (okone(i, j)) exista[i][j] = true;
            else exista[i][j] = false;
        }
    }

    for (int i = 0; i < STATE; i++)
    {
        for (int j = 0; j < STATE; j++)
        {
            if (okanother(i, j)) existb[i][j] = true;
            else existb[i][j] = false;
        }
    }

    for (int i = 0, a, temp; i < STATE; i++)
    {
        temp = 0;
        a = i;
        while (a)
        {
            if (a & 1) temp++;
            a >>= 1;
        }
        results[i] = temp;
    }
}

void solve()
{
    memset(dp, 0, sizeof(dp));
    dp[0][0][0][0] = 1;
    cu = 0, ne = 1;
    ans = 0;

    for (int i = 0; i < ROW - 1; i++)
    {
        for (int j = 0; j <= m; j++)
        {
            for (int k = 0; k < STATE; k++)
            {
                if ((!yes(k, i - 1)) && i >= 2) continue;
                for (int l = 0; l < STATE; l++)
                {
                    if (!yes(l, i) && i >= 1) continue;
                    if (dp[cu][j][k][l] == 0) continue;

                    for (int o = 0; o < STATE; o++)
                    {
                        if (!yes(o, i + 1)) continue;
                        if (j + results[o] > m) continue;
                        if (i >= 2 && !exista[k][l]) continue;
                        if (i >= 1 && !exista[l][o]) continue;
                        if (i >= 2 && !existb[k][o]) continue;
                        dp[ne][j + results[o]][l][o] += dp[cu][j][k][l];
                    }
                }
            }
        }
        memset(dp[cu], 0, sizeof(dp[cu]));
        swap(cu, ne);
    }

    for (int i = 0; i < STATE; i++)
    {
        for (int j = 0; j < STATE; j++)
        {
            ans += dp[cu][m][i][j];
        }
    }

    printf("%I64d\n", ans);
}

void input()
{
    init();

    scanf("%d", &cases);

    while (cases--)
    {
        scanf("%d\n", &m);
        memset(cur, 0, sizeof(cur));

        for (int i = 1; i < ROW; i++)
        {
            scanf("%s", mt[i]);
            for (int j = 0; j < COL; j++)    //记录皇后位置
            {
                if (mt[i][j] == '*') cur[i] += (1 << (COL - j - 1));
            }
        }

        solve();
    }
}

int main()
{
    input();
    return 0;
}
g++提交
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值