[Remarks] Do you have a lot of optimizations, DP?

This blog is used to store various DP optimization questions, because it is ZZstill learning, so this blog will be continuously updated as the questions progress.

State compression optimization

The so-called state compression is to compress the state that originally needed many and many dimensions to describe it, even the violence is not clearly described into one dimension.
The time complexity of general (2 n \ cdot n ^ ^ 2) to O $ form
( ZZand less likely to computational complexity, the complexity of the blog if there is an error, please point out to me and I enjoy sarcasm , thank you!)
Horizons pole Narrow ZZjust heard the name before ... Thanks to Lrefrain Senior for introducing this thing to me %%%
Common scenarios of using state compression optimization:

How come this data range is surprisingly small in one dimension?

Non-aggression

It should be the most classic pressure dp. Seeing this very unique data range, most
of the possible states of each row can be compressed. Because each position is either placed or not placed, we put Marked 1, not marked 0, then for a row, each state can be represented by a binary string, great! ! !
Even better, since binary is used, you can use the bitwise operation <<, >>and the &operator, to directly determine whether the state of the two adjacent lines is illegal!
This really needs to be understood, the better the better!
Let's put the code, but the more important thing is to understand the spirit!

#include<bits/stdc++.h>
using namespace std;
#define MA 1005
#define ll long long

ll sit[MA]={0},ku[MA]={0};
ll cnt=0;
ll n,k;
ll dp[15][MA][100]={0};

int main()
{
	scanf("%lld%lld",&n,&k);
	for(int i=0;i<(1<<n);i++)
	{
		if(i&(i<<1))continue;
		sit[++cnt]=i;
		for(int j=0;j<n;j++)
		{
			if(i&(1<<j))ku[cnt]++;
		}
	}
	dp[0][1][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=cnt;j++)
		{
			for(int p=ku[j];p<=k;p++)
			{
				for(int q=1;q<=cnt;q++)
				{
					if(sit[j]&sit[q])continue;
					if(sit[j]&(sit[q]>>1))continue;
					if(sit[j]&(sit[q]<<1))continue;
					dp[i][j][p]+=dp[i-1][q][p-ku[j]];
				}
			}
		}
	}
	ll ans=0;
	for(int i=1;i<=cnt;i++)
	{
		ans+=dp[n][i][k];
	}
	printf("%lld",ans);
	return 0;
}

A little trick from the seniors

When using \ (lowbit \) or enumeration to calculate the number of \ (1 \) in the \ (01 \) string , if there are many strings to be calculated, it may cause the algorithm complexity to explode here and get stuck . You can use the preprocessing method to calculate the number of \ (1 \) in all states first . When you use it, you can directly \ (O (1) \) query ~

Artillery position

If you find that you have to think about it, what should you do?
First of all, in fact, considering the following is equivalent to the following consideration, so there is no need to consider the following (a bit of winding).
Then, because the above only needs to stretch two grids, it is directly expressed in two dimensions \ (i \) , \ (i-1 \) The status of the line can be transferred every time from \ (i-1 \) , \ (i-2 \) !
The question also needs to consider a plain question. Here we also compress the terrain of each line. When performing dp, pay attention to determine whether the status is legal (≧ ▽ ≦) /
dp part (in fact, it is a bit troublesome to write, but Looks neat)

	for(int i=1;i<=cnt;i++)
	{
		if(sit[i]&pa[1])continue;
		dp[1][i][0]=max(dp[1][i][0],mu[i]);
	}
	for(int i=1;i<=cnt;i++)
	{
		if(sit[i]&pa[1])continue;
		for(int j=1;j<=cnt;j++)
		{
			if(sit[j]&pa[2])continue;
			if(sit[j]&sit[i])continue;
			dp[2][j][i]=max(dp[2][j][i],mu[i]+mu[j]);
		}
	}
	for(int i=3;i<=n;i++)
	{
		for(int j=1;j<=cnt;j++)
		{
			if(sit[j]&pa[i])continue;
			for(int k=1;k<=cnt;k++)
			{
				dp[i%3][j][k]=0;
				if(sit[k]&pa[i-1])continue;
				if(sit[j]&sit[k])continue;
				for(int l=1;l<=cnt;l++)
				{
					if(sit[l]&pa[i-2])continue;
					if(sit[j]&sit[l])continue;
					if(sit[k]&sit[l])continue;
					
					dp[i%3][j][k]=max(dp[i%3][j][k],dp[(i-1)%3][k][l]+mu[j]);
				}
			}
		}
	}

Special checkerboard

After having the foundation of the first two questions, this question should be a difficult one. It is put in the back because when I did it, I found a solution (self-sensing) to
observe the whole question more beautifully. Put a car, which means that it is impossible to have the same state on two different lines, that is, each state on the board is different for each line,
so I think, since they are all different, can you not maintain the number of lines Reduce space to one dimension? After thinking, this can be achieved.
We use \ (sit [p] \) to represent a state of a certain line, then just delete one in this state 1, you can get a state of the previous line, we only need to enumerate each one 1, and then delete him The answer obtained in a certain state on the previous line can be updated on this line. The deletion here can be easily achieved with XOR operation, which is really wonderful!
By counting 1the number, we get the line number, and 1the position we enumerate to +1 can get the column number. If this coordinate is legal, we will update the answer. (Note this +1 !)
The code at the time: (May be some details are slightly different from the above, but the idea is the same)

#include<bits/stdc++.h>
using namespace std;
#define ll long long

ll n,m;
ll dp[1<<21]={0};
ll a[25][25]={0};
ll x,y;
ll z[1<<21]={0};

int main()
{
	for(int i=1;i<=(1<<21);i++)
	{
		z[i]=z[i>>1]+(i&1);
	}
	scanf("%lld%lld",&n,&m);
	while(m--)
	{
		scanf("%lld%lld",&x,&y);
		a[x][y-1]=1;
	}
	dp[0]=1;
	for(int i=1;i<(1<<n);i++)
	{
		for(int j=0;j<n;j++)
		{
			if((i&(1<<j))&&!a[z[i]][j])
			{
				dp[i]+=dp[i^(1<<j)];
			}
		}
	}
	printf("%lld",dp[(1<<n)-1]);
	return 0;
} 

Monotone queue optimization

It ’s too late to whisper, or I wo n’t get up early.

Guess you like

Origin www.cnblogs.com/zzzuozhe-gjy/p/12741619.html