AcWing 1064. Little King

insert image description here
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 8in grids cannot be placed.

As shown below
insert image description here

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 irow , 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
snsn011

Attribute : Countnumber 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 2row (the last difference), without any restrictions, there are at most 2 ^ ndifferent 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、2line is a legal situation

insert image description here
For the first property, we can write a checkfunction 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 2the property be implemented in code? Let the penultimate 1row state be a, and the penultimate 2row state be b.

Then satisfy:

  • (a & b) == 0
  • (a | b) There cannot be two adjacent ones 1 , 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 irow , and ithe status of athe first i-1row is bthat all the plans jof .

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-1row has been placed, and the state of the first i-1row is that ( indicates the number of ) all the king's plans bhave been placedj-Count(a)Count(a)a1 : 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.
insert image description here

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 shmaximum 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 vectorarray ,state

  • Use headtwo-dimensional variable-length array to preprocess the states that can be legally transferred to each other, such as head[a] = bindicates that state acan be blegally

  • cntArray Preprocessing How many bits in each binary compressed state are1

  • ②About the initialization state

  • Three-dimensional dparray , 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 dparray , we can proceed according to the actual situation, which means that dp[0][0][0]the front 0row , and the number of kings is placed, and the 0last row is 0the number of solutions. * Obviously, there can be a 1legal solution in this case, and the initialization is 1ie 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 asf[n+1, k, 0]

  • The state is represented as: n+1considering the chessboard on the previous n+1layer, where k kings are placed on the previous layer, and nothing is placed on the first n+1layer

  • According to the state transfer we mentioned earlier, this state will transfer all legal states to the nlayer 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;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324142061&siteId=291194637