[bzoj1087] little kings

[bzoj1087] little kings

题目描述

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

输入格式

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出格式

一行,一个整数,表示答案。

样例数据

input

3 2

output

16

数据规模与约定

N<=10

看到数据范围,首先考虑暴搜和状压

我们用f[i][k][j]表示当前在第i行,已经放置了k个国王,且当行状态为j的方案数

首先我们可以枚举所有的状态,并将没有相邻两个1的状态存入一个集合S

然后我们预处理一下从每一个S中的状态i的上一行可能是那些状态

j是i的上一行当且仅当

1:没有任意一位上i和j都是1,因为国王会攻击到他上面(或下面),及i&j==0;

2 :没有任意相邻两位上有两个1

       例如    i: 1      0  是不合法的    i: 1     0 是合法的

                 j:   0     1                        j: 0     1

因为国王会攻击到他左上左下右上右下的格子,这一判断即check(S[i]|S[j]); 其中check为判断是否有两个相邻的1

所以预处理就是

    for(int i=0;i<S.size();i++)
    {
        for(int j=0;j<S.size();j++)
        {
            if(check(S[i]|S[j])&&(S[i]&S[j])==0) 
			To[S[i]].push_back(S[j]);
        }
    }

这就表示状态S[i]的上一行可以是S[j];

那状态转移方程就很简单了

f[i][k][j]=f[i][k][j]+f[i-1][k-count[j][l];

其中count[j]表示状态j的二进制数里有几个1(即对应了有几个国王),这个可以预处理出来

所以我们一层循环枚举i,一层循环枚举k,一层循环枚举j,在通过预处理出来的To数组求出l

初值f[0][0][0]=1;

完整代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long  ll;
int n,m; 
int Count[1<<10]; 
vector<int> S;  
vector<int>To[1<<10];
ll f[12][120][1<<10];
bool check(int x)    
{
    for(int i=0;i<n;i++)
    {
        if((x>>i&1)&&(x>>(i+1)&1)) 
        return false;
    }
    return true;
 }
int main()
{
	freopen("king.in","r",stdin);
	freopen("king.out","w",stdout);
    cin>>n>>m;
    for(int i=0;i<1<<n;i++)
    {
        if(check(i)) S.push_back(i);
        for(int j=0;j<n;j++)
        {
        	if(i>>j&1) 
        	Count[i]++;
		}
    }
    for(int i=0;i<S.size();i++)
    {
        for(int j=0;j<S.size();j++)
        {
            if(check(S[i]|S[j])&&(S[i]&S[j])==0) 
			To[S[i]].push_back(S[j]);
        }
    }
    f[0][0][0]=1;
    for(int i=1;i<=n+1;i++)
    {
        for(int k=0;k<=m;k++)
        {
            for(int t=0;t<S.size();t++)
            {
                int a=S[t];
                for(int j=0;j<To[a].size();j++) 
                {
                     int b=To[a][j];
                     if(k>=Count[a])
                     {
                        f[i][k][a]+=f[i-1][k-Count[a]][b];
                     }
                }
            }
        }
    }
    cout<<f[n+1][m][0];
    return 0;
} 

 

猜你喜欢

转载自blog.csdn.net/jwg2732/article/details/113825133
今日推荐