现在的位置: 首页 > 综合 > 正文

SGU——223. Little Kings

2019年02月15日 ⁄ 综合 ⁄ 共 2058字 ⁄ 字号 评论关闭

223. Little Kings

time limit per test: 0.5 sec.
memory limit per test: 65536 KB
input: standard
output: standard

After solving nice problems about bishops and rooks, Petya decided that he would like to learn to play chess. He started to learn the rules and found out that the most important piece in the game is the king.

The king can move to any adjacent cell (there are up to eight such cells). Thus, two kings are in the attacking position, if they are located on the adjacent cells.

Of course, the first thing Petya wants to know is the number of ways one can position k kings on a chessboard of size n × n so that no two of them are in the attacking position. Help him!

Input
The input file contains two integers n (1 ≤ n ≤ 10) and k (0 ≤ k ≤ n2).
Output
Print a line containing the total number of ways one can put the given number of kings on a chessboard of the given size so that no two of them are in attacking positions.
Sample test(s)
Input
Test #1

3 2

Test #2

4 4

Output
Test #1

16

Test #2

79

 

人生第一题状压DP(一边看资料一边学习过去),用状态f[i][j][k] 表示第i行状态是j,且前i行放置了k个棋子的方案数

则 f[i][j][k]  = f[i - 1][p][k - c[j]]

枚举符合条件的j和p,其中我们用s[j]表示第j个状态,用c[j]表示状态j里1的个数(1对应棋子),s数组和c数组可以事先用dfs预处理

如何判断2个状态可以共存?

s[j] & s[p] == 0 也就是说这两个状态在同一位上不会同时为1,但是这还不够,题目说king可以攻击周围8个棋子,所以我们需要对对角线进行判断,其实很简单,我们把s[p] << 1 ,>>1就可以判断了,<<1相当于在最后补一个0,那么此时两个状态进行&时,s[j]相当于往右偏移一位,>>1同理,这样就把对角线也判断进去了,剩下的就没问题了

#include <set>
#include <map>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

long long dp[15][1000][150];
long long  s[5055];
long long c[5055];
int n;
int res;

bool is_ok(int a, int b)
{
    if( s[a] & s[b] )
    {
        return false;
    }
    if( (s[a] << 1) & s[b] )
    {
        return false;
    }
    if( (s[b] << 1) & s[a] )
    {
        return false;
    }
    return true;
}

void dfs(int l, int state, int cnt_1)
{
    if(l == n)
    {
        s[++res] = state;
        c[res] = cnt_1;
        return ;
    }
    dfs(l + 1, state << 1, cnt_1);
    if( (state & 1) == 0 )
    {
        dfs(l + 1, (state << 1) | 1, cnt_1 + 1);
    }
}

int main()
{
    int k;
    while (~scanf("%d%d", &n, &k))
    {
        res = 0;
        dfs(0, 0, 0);
        memset (dp, 0, sizeof(dp) );
        dp[0][1][0] = 1;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= res; ++j) // 枚举第i行的状态
            {
                for (int pn = c[j]; pn <= k; ++pn) //枚举前i行已经放置的总的棋子数
                {
                    for (int p = 1; p <= res; ++p)
                    {
                        if ( is_ok(j, p) )
                        {
                            dp[i][j][pn] += dp[i - 1][p][pn - c[j]];
                        }
                    }
                }
            }
        }
        long long  ans = 0;
        for (int i = 1; i <= res; ++i)
        {
            ans += dp[n][i][k];
        }
        printf("%lld\n", ans);
    }
    return 0;
}

抱歉!评论已关闭.