問題#
[SCOI2005] 互不侵犯#
問題の説明#
$N \times N$ のチェスボードに $K$ 個の王を置き、彼らが互いに攻撃しないようにする配置は何通りあるか。王は上下左右、および左上、左下、右上、右下の 8 つの方向に近くの各 1 マスを攻撃できる。合計で $8$ マス。
すべてのデータに対して、$1 \le N \le 9$、$0 \le K \le N\times N$。
解法#
f[i][j][k]
を第 i 行まで進めたとき、これまでに j 個の王を選び、第 i 行の状態が k である配置の数を表すとする。
次に i,j,k
と前の行の状態を列挙して遷移させればよい。
問題#
-
long long
を開かないと祖先に会えない。 -
第二の位置は
N * N
を開く必要がある!
コード#
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read()
{
int f = 1, x = 0;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return f * x;
}
const int N = 10;
int f[N][N * N][1 << 9];
int sum[1 << 9];
int n, k;
int getsum(int x)
{
int ans = 0;
while(x)
{
x &= (x - 1);
ans++;
}
return ans;
}
signed main()
{
for(int i = 0;i < (1 << 9);i++)
{
sum[i] = getsum(i);
}
n = read(), k = read();
for(int s = 0;s < (1 << n);s++)
{
f[1][sum[s]][s] = 1;
}
for(int i = 2;i <= n;i++)
{
for(int j = 0;j <= k;j++)
{
for(int s = 0;s < (1 << n);s++)
{
if((s >> 1) & s || (s << 1) & s || sum[s] > j) continue;
for(int fl = 0;fl < (1 << n);fl++)
{
if((fl >> 1) & fl || (fl << 1) & fl || (fl << 1) & s || fl & s || (fl >> 1) & s || sum[fl] + sum[s] > j) continue;
f[i][j][s] += f[i - 1][j - sum[s]][fl];
}
}
}
}
long long ans = 0;
for(int s = 0; s < (1 << n);s++)
{
if((s >> 1) & s) continue;
ans += f[n][k][s];
}
cout << ans;
return 0;
}