SCOI2005互不侵犯King

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1499  Solved: 872
[Submit][Status]

Description

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

Input

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

Output

方案数。

Sample Input

3 2

Sample Output

16

HINT

 

Source

题解:

终于A了这道题。。。

其实意识到对安放的国王总个数有限制,那就应该是DP了

又因为是在棋盘上,所以以每行为状态进行转移

又因为n很小,所以状压DP。。。

主要是做一些预处理

代码:

 1 var  tot,n,i,j1,j2,j,k,l:longint;
 2      s:ansistring;
 3      ans:int64;
 4      a:array[0..1000,0..1000] of boolean;
 5      f:array[0..10,0..1000,0..100] of longint;
 6      can:array[0..1000] of boolean;
 7      calc:array[0..1000] of longint;
 8 function check(x,y:longint):boolean;
 9  var s1,s2:ansistring;
10      i:longint;
11   begin
12     s1:=binstr(x,n);
13     s2:=binstr(y,n);
14     for i:=1 to n do
15      if (s1[i]='1') and ((s2[i-1]='1') or (s2[i]='1') or (s2[i+1]='1')) then exit(false);
16     exit(true);
17   end;
18 function cann(x:longint):boolean;
19  var s:ansistring;
20      i:longint;
21   begin
22     s:=binstr(x,n);
23     for i:=2 to n do if (s[i]='1') and (s[i]=s[i-1]) then exit(false);
24     exit(true);
25   end;
26 
27 procedure init;
28  begin
29    readln(n,k);
30    tot:=1<<n-1;
31    for i:=0 to tot do
32     begin
33       calc[i]:=0;
34       s:=binstr(i,n);
35       for j:=1 to n do if s[j]='1' then inc(calc[i]);
36     end;
37    fillchar(f,sizeof(f),0);
38    for i:=0 to tot do f[1,i,calc[i]]:=1;
39    for i:=0 to tot do
40     if cann(i) then can[i]:=true;
41   for i:=0 to tot do
42    if can[i] then
43     for j:=0 to tot do
44      if can[j] then
45       if check(i,j) then a[i,j]:=true;
46   //for i:=1 to tot do writeln(can[i],' ',calc[i]);
47  end;
48 procedure main;
49  begin
50    for i:=2 to n do
51      for j1:=0 to tot do
52       if can[j1] then
53        for l:=calc[j1] to k do
54         for j2:=0 to tot do
55          if (can[j2]) and (a[j1,j2]) then
56           inc(f[i,j1,l],f[i-1,j2,l-calc[j1]]);
57   // for i:=1 to n do
58   //  for j:=0 to tot do
59   //   for l:=1 to n do writeln(f[i,j,l]);
60    ans:=0;
61    for i:=0 to tot do if can[i] then inc(ans,f[n,i,k]);
62    writeln(ans);
63   end;
64 begin
65   assign(input,'input.txt');assign(output,'output.txt');
66   reset(input);rewrite(output);
67   init;
68   main;
69   close(input);close(output);
70 end.                          
View Code
原文地址:https://www.cnblogs.com/zyfzyf/p/3889148.html