Learning about State Compression

 Check the number of squares (1)

Problem - 1565

Idea: Use binary to represent the state of taking or not taking each line. There are a total of 20 lines, which is 2 to the 20th power (1048576)

First screen out the non-adjacent states between each row in these 1048576 states, that is, i&(i>>1)==0 is a legal state.

Then screen out the legal state, no more than 2e4.

Traverse each line, assuming that the state of a line is j, then assuming that the previous line is k, when judging tot[j]&tot[k]==0 , take dp[i][j]=max(dp[i][j ],dp[i-1][k]+va);

Last take for(int i=1;i<=tt;i++)ma=max(ma,dp[n][i]);

code:

#include<bits/stdc++.h>
using namespace std;
int n,m;int mp[30][30];
int dp[25][20000];int tot[20000];
int fin(int x,int y){
     int sum=0;int t=1;
     while(y){
          if(y&1){
               sum+=mp[x][t];
          }
          y=y>>1;
          t++;
     }
     return sum;
}
void solve(int n){
     int tt=0;
     memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>mp[i][j];
     for(int i=0;i<(1<<n);i++){
          if((i&(i>>1))==0){tot[++tt]=i;}//每一列的状况 少于2e4
     }
     for(int i=1;i<=n;i++){
          for(int j=1;j<=tt;j++){
               int va=fin(i,tot[j]);//如果当前的j的状态
               for(int k=1;k<=tt;k++){
                    if((tot[j]&tot[k])==0)
                         dp[i][j]=max(dp[i][j],dp[i-1][k]+va);
               }
          }
     }
     int ma=0;
     for(int i=1;i<=tt;i++)ma=max(ma,dp[n][i]);
     cout<<ma<<'\n';
}
signed main()
{
     int n;while(cin>>n){solve(n);}
     return 0;
}

Mondrian's dream 

2411 -- Mondrian's Dream

Idea: refer to poj2411 chessboard coverage

Let’s say 11 is placed horizontally, and 01 is placed vertically. If the current is [i, j]

Case 1: [i-1, j] is 0, then [i, j] is 1 (this is certain)

Case 2: [i-1, j] is 1, then [i, j] is 0

Case 3: [i-1, j] is 1, then [i, j] is 1

But if according to the above situation, then

01

11

Such a situation is not in compliance with the requirements

There is no problem for case two, but not for case three (such as the above example)

11

00

11 (case 2)

So the third case is changed to

Row i-1, j-1, j-column are all 1, row i-th j-1, j-column are all 1.

 Know the general idea, then you can start to do it.

Set dp【200005】【20】, where the left one is the state of one row, and the right one is the number of rows

First fill in the numbers from 0 to (1<<m)-1,

But if a number like 010 appears, it is not in compliance with the specification, so such a number is not needed

So the initialization is complete.

Then, according to the above three conditions, start to deduce the condition of r in the next row according to the condition of r-1 in the previous row, and finally push each column, then add dp[s][r to the number of schemes of current state scur -1]

Finally, because the last line is full, the last line is all 1, so output dp[(1<<m)-1][n-1] is the final answer.

the code

#include<iostream>
using namespace std;
long long dp[200005][22];
int n,m;
bool check(int x){
     while(x){
          if((x&1)&&(x&2))x>>=2;
          else if((x&1)==0)x=x>>1;
          else return false;
     }
     return 1;
}
void dfs(int r,int c,int s,int scur){ //搜索r-1行状态s可以r行匹配的所有状态scur
    if(c>m) return;
    if(c==m) {
          dp[scur][r]+=dp[s][r-1];
          return;
    }
    if(s>>c&1){
        dfs(r,c+1,s,scur); //1->0
        if(s>>c&2)
            dfs(r,c+2,s,scur|3<<c); //11->11
    }
    else dfs(r,c+1,s,scur|1<<c); //0->1
}
int main()
{
    while(cin>>n>>m,n){
        if(n*m&1) {puts("0");continue;}
        if(m>n)swap(m,n);
        memset(dp,0,sizeof dp);
        for(int i=0;i<(1<<m);i++)
            if(check(i))dp[i][0]=1;
        for(int i=1;i<n;i++)
            for(int j=0;j<(1<<m);j++)
                dfs(i,0,j,0);
          cout<<dp[(1<<m)-1][n-1]<<endl;
     }
     return 0;
}

91. Shortest Hamiltonian path

91. Shortest Hamiltonian Path - AcWing Question Bank 

Ideas:

The final end state is status=(1<<n)-1, and the number label is n-1

 The idea of ​​state transition is

The current state is i, I want to go to the point j, then I need to select a point that has been passed from the road that has already been passed, and then take the minimum value

Each state is from 0 to (1<<n)-1, and then traverse each point j, traverse the corresponding point k, and find the minimum value.

the code

#include<bits/stdc++.h>
using namespace std;
int mp[25][25];
long long f[(1<<20)][25];
int main()
{
     memset(f, 0x3f, sizeof(f));
     int n;cin>>n;
     for(int i=0;i<n;i++)for(int j=0;j<n;j++)cin>>mp[i][j];
     f[1][0]=0;
     for(int i=0;i<(1<<n);i++){
          for(int j=0;j<n;j++){
               if(i&(1<<j)){//代表当前状态是有j的
                    for(int k=0;k<=n;k++){
                         if(k==j)continue;
                         if(i&(1<<k)){//如果有k的话
                              f[i][j]=min(f[i][j],f[i-(1<<j)][k]+mp[k][j]);
                         }
                    }
               }
          }
     }
     cout<<f[(1<<n)-1][n-1];
     return 0;
}

P1896 [SCOI2005] Nonaggression

P1896 [SCOI2005] Nonaggression - Luogu

 

Guess you like

Origin blog.csdn.net/zy98zy998/article/details/128001410