This question is " Constrained placement of tic-tac-toe", that is, no chess pieces can be placed around the current position .8
Title:
As the title.
Ideas:
Problem limitation: When a king is placed 8
in grids cannot be placed.
As shown below
The way the current row is placed is only related to the previous row . If you think about it carefully, you can know that no matter how the upper row is placed, it will not affect the current row .
State representation: f[i, j, s] three-dimensional representation
Set : All the plan sets that are only placed in the front i
row , currently placed chessj
pieces, and the status of the last row is ( is a binary number, if the chessboard has columns , then is a binary number of bits , indicating a vacancy, indicating a )s
s
n
s
n
0
1
1
Attribute : Count
number of plans
State calculation :
f[i, j, s]
Set division : the current state of the last row has been determined, and our set division is based on the state of the penultimate 2
row (the last difference), without any restrictions, there are at most 2 ^ n
different situations
For the state of the penultimate line , two properties need to be satisfied according to the meaning of the question: first , the two kings cannot be adjacent to each other, and secondly , it is restricted by the state of the last line (and the last line cannot attack each other), for example, the situation of the penultimate 1、2
line is a legal situation
For the first property, we can write a check
function to determine whether it is satisfied:
bool check(int st)
{
for(int i=0; i<n-1; ++i)
{
if((st>>i&1) && (st>>(i+1)&1)) return false;
}
return true;
}
So how can 2
the property be implemented in code? Let the penultimate 1
row state be a
, and the penultimate 2
row state be b
.
Then satisfy:
(a & b) == 0
(a | b)
There cannot be two adjacent ones1
, i.e.:check( a | b ) = true
If a certain type of subset in the set only satisfies two properties , the number of this type of scheme can be directly added . For the number of this type of scheme, we can analyze it as follows:
The meaning of this type of set: the front i
row , and i
the status of a
the first i-1
row is b
that all the plans j
of .
We can use the idea of a mapping . Since the last row of all schemes in this subset is in the same state a
, when calculating the number of schemes, the last row of each scheme can be removed first .
That is to say that the front i-1
row has been placed, and the state of the first i-1
row is that ( indicates the number of ) all the king's plans b
have been placedj-Count(a)
Count(a)
a
1
: f[i-1, j-Count(a), b]
.
It can be seen from this that the number of digits of a binary number needs to be calculated, which can be implemented by using c++
the built-in function of , or by coding as follows:
int count(int st)
{
int cnt = 0;
for(int i=0; i<n; ++i)
{
if(st>>i&1) ++cnt;
}
return cnt;
}
Then count the number of solutions. At this time, the number of solutions is also correct. The two are in a one-to- one mapping relationship.
When finally calculating the target value f[i, j, s]
, it is only necessary to add together all the subsets that satisfy the two properties.
time complexity:
Formula : number of states × calculation amount of state transition
Number of rows (i: 10) × number of kings (j: 100) × number of all legal states (s: worst case 2^10) × number of legal transitions per state (sh: up to 1000 transitions) =1e9
It is a very dangerous time complexity to calculate, but we found that not all states are legal, because there are very few states that satisfy "each row cannot have adjacent " 1
. Through programming, we found that, s
, The sh
maximum product is 1365
, so in fact the time complexity of this problem is very small, about only 1e6
.
Code:
Some details of the code :
-
①About preprocessing
-
We preprocess all legal (two and two kings are not adjacent) states with an
vector
array ,state
-
Use
head
two-dimensional variable-length array to preprocess the states that can be legally transferred to each other, such ashead[a] = b
indicates that statea
can beb
legally -
cnt
Array Preprocessing How many bits in each binary compressed state are1
-
②About the initialization state
-
Three-dimensional
dp
array , the first dimension represents the number of rows currently placed, the second dimension represents the number of placed kings, and the third dimension represents the state of the last row -
For the initialization of the
dp
array , we can proceed according to the actual situation, which means thatdp[0][0][0]
the front0
row , and the number of kings is placed, and the0
last row is0
the number of solutions. * Obviously, there can be a1
legal solution in this case, and the initialization is1
ie Can. -
③ Output about the target state (answer)
-
We can observe that if none of the pawns of the current layer are placed, i.e.
state=(000000)
, then all legal states are legal transition states of that state -
That is to say: as long as nothing is placed on this layer, as long as the upper layer is legal, it can definitely be transferred to this state of this layer.
-
So we can set the target state as
f[n+1, k, 0]
-
The state is represented as:
n+1
considering the chessboard on the previousn+1
layer, where k kings are placed on the previous layer, and nothing is placed on the firstn+1
layer -
According to the state transfer we mentioned earlier, this state will transfer all legal states to the
n
layer to itself. -
So in the end we do n't need to enumerate all the target states additionally
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 12, K = N * N, M = 1<<N;
int n, k;
vector<int> state;
vector<int> head[M];
int cnt[M];
int dp[N][K][M];
bool check(int st)
{
for(int i=0; i<n-1; ++i)
{
if((st>>i&1) && (st>>(i+1)&1)) return false;
}
return true;
}
int count(int st)
{
int cnt = 0;
for(int i=0; i<n; ++i)
{
if(st>>i&1) ++cnt;
}
return cnt;
}
signed main()
{
cin>>n>>k;
for(int i=0; i<1<<n; ++i)
{
if(check(i)) state.push_back(i), cnt[i] = count(i);
}
for(int i=0; i<state.size(); ++i)
{
for(int j=0; j<state.size(); ++j)
{
int a = state[i], b = state[j];
if(!(a&b) && check(a|b)) head[a].push_back(b);
}
}
dp[0][0][0] = 1;
for(int i=1; i<=n+1; ++i)
{
for(int j=0; j<=k; ++j)
{
for(auto a : state)
{
for(auto b : head[a])
{
int c = cnt[a];
if(j>=c)
{
dp[i][j][a] += dp[i-1][j-c][b];
}
}
}
}
}
cout<<dp[n+1][k][0]<<endl;
return 0;
}