Plug dp summary

Keywords: dp

pd head plug

purpose

Plug dp is mainly used to solve the dynamic programming problem based on connectivity state compression. Generally speaking, it is to solve the problem of the number of loop schemes in a grid graph, and the data range is small, such as This template

method

Define plug: whether the path passes through the edge of the grid point. As shown in the figure, it is a left plug

It is not difficult to find that there are only two plugs for all points on a circuit, as shown in the figure

So I will pop search \ (\ Theta(6^{nm}) \)

This is obviously unrealistic. Consider dp transfer

Transferred object

Consider the transfer contour, that is, a line that separates the semi graph we have considered and the semi graph we have not considered, such as the green line in the figure, and the blue line indicates that it has been considered

Generally speaking, we adopt grid by grid recursion (in a few cases, we will consider row by row recursion)

Representation of status

Minimum representation

The obstacle is 0, the number in the first connected block is 1, and the number in the second connected block is 2

(another method is to mark each connected block with the leftmost column number)

Bracket notation

There are four plugs a, b, C and D on the contour line from left to right. If a and C are connected and not connected with b, b and D must not be connected. (applicable to all chessboard problems, see CDQ paper for details)

It is not difficult to think of bracket matching. 0 represents no bracket, 1 represents left bracket, and 2 represents right bracket (in the implementation, hexadecimal is generally used, and bit operation is really fragrant)

Some trival details

It is generally considered to scroll dp with map or hash, otherwise the memory will explode

Approximate mode

That is, the classification is crazy and tired. There are only six cases in a grid: up and down, left and right, up left, up right, down left and down right, so the discussion is over and the code of the template is pasted

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

namespace DEBUG {
	void debug_out() { cerr << '\n'; }
	template <typename Head, typename... Tail>
	void debug_out(Head H, Tail... T) { cerr << ' ' << H, debug_out(T...); }
#define debug(...) cerr << '[' << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
} using namespace DEBUG;
typedef long long ll;
typedef unsigned long long ull;
//#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
namespace get_out
{
	char B[1<<15],*S=B,*T=B;
	char op;
	inline void read_(int &x)
	{
		x=0;
		int fi(1);
		op=getchar();
		while((op<'0'||op>'9')&&op!='-') op=getchar();
		if(op=='-') op=getchar(),fi=-1;
		while(op>='0'&&op<='9') x=(x<<1)+(x<<3)+(op^48),op=getchar();
		x*=fi;
		return;
	}
	inline void read_(long long &x)
	{
		x=0;
		int fi(1);
		op=getchar();
		while((op<'0'||op>'9')&&op!='-') op=getchar();
		if(op=='-') op=getchar(),fi=-1;
		while(op>='0'&&op<='9') x=(x<<1)+(x<<3)+(op^48),op=getchar();
		x*=fi;
		return;
	}
	inline void read_(double &x)
	{
		x=0.0;
		float fi(1.0),sm(0.0);
		op=getchar();
		while((op<'0'||op>'9')&&op!='-') op=getchar();
		if(op=='-') op=getchar(),fi=-1.0;
		while(op>='0'&&op<='9') x=(x*10.0)+(op^48),op=getchar();
		if(op=='.') op=getchar();
		int rtim=0;
		while(op>='0'&&op<='9') sm=(sm*10.0)+(op^48),++rtim,op=getchar();
		while(rtim--) sm/=10.0;
		x+=sm,x*=fi;
		return;
	}
	inline void postive_write(int x)
	{
		if(x>9) postive_write(x/10);
		putchar(x%10|'0');
	}
	inline void postive_write(long long x)
	{
		if(x>9) postive_write(x/10);
		putchar(x%10|'0');
	}
	inline void write_(int x)
	{
		if(x<0) x=-x,putchar('-');
		postive_write(x);
	}
	inline void write_(int x,char ch)
	{
		write_(x),putchar(ch);
	}
	inline void write_(long long x)
	{
		if(x<0) x=-x,putchar('-');
		postive_write(x);
	}
	inline void write_(long long x,char ch)
	{
		write_(x),putchar(ch);
	}
}
using get_out::read_;
using get_out::write_;
#define maxn 15
#define inf 0x7f7f7f7f
#define mod 299993
#define hashMaxNum 300000

int n,m,head[hashMaxNum];
int cnt[2],mp[maxn][maxn],edi,edj,now,la;
ll ans=0;

class hahaha
{
	public:
		int s[20];
		hahaha()=default;
		hahaha(int state)
		{
			s[0]=state&3;
			for(int i=1;i<=m;++i) s[i]=(state>>(i<<1))&3;
		}
		inline int rar()
		{
			int state=0;
			for(int i=1;i<=m;++i) state|=s[i]<<(i<<1);
			return (state|s[0]);
		}
};

inline hahaha unpack(int state) {return hahaha(state);}
inline int rar(hahaha &H){return H.rar();}

class hash_T
{
	public:
		int state[2],nex;
		ll num[2];
		hash_T()=default;
}s[hashMaxNum];

inline void insert(int state,ll num)
{
	int tmp=state%mod;
	for(int i=head[tmp];i;i=s[i].nex)
		if(state==s[i].state[now])
		{
			s[i].num[now]+=num;
			return;
		}
	s[++cnt[now]].state[now]=state,
	s[cnt[now]].nex=head[tmp],
	s[head[tmp]=cnt[now]].num[now]=num;
}
hahaha now_state,_k;
ll lnum;

inline void zip_insert()
{
	insert(rar(_k),lnum),_k=now_state;
}

inline void solve()
{
	register int i,j,k;
	int west,north;
	insert(0,1);
	for(i=1;i<=n;++i) for(j=1;j<=m;++j)
	{
		la=now,now^=1;//renew state
		cnt[now]=0,memset(head,0,sizeof(head));//init
		for(k=1;k<=cnt[la];++k)
		{
			now_state=unpack(s[k].state[la]),_k=now_state;
			lnum=s[k].num[la],west=now_state.s[0],north=now_state.s[j];
			if(!mp[i][j]) {if(!west&&!north) insert(rar(_k),lnum);continue;}
			if(!west&&!north)
			{
				if(mp[i][j+1]&&mp[i+1][j])
					_k.s[0]=2,
					_k.s[j]=1,//Hang up 
					zip_insert();
				continue;
			}
			if(!west&&north)
			{
				if(mp[i+1][j])
					insert(rar(_k),lnum);
				if(mp[i][j+1])
					_k.s[0]=north,
					_k.s[j]=0,
					zip_insert();
				continue;
			}
			if(west&&!north)
			{
				if(mp[i][j+1])
					insert(rar(_k),lnum);
				if(mp[i+1][j])
					_k.s[0]=0,
					_k.s[j]=west,
					zip_insert();
				continue;
			}
			if(west==1&&north==2)
			{
				_k.s[0]=_k.s[j]=0;
				bool flag=0;
				for(int pos=0;pos<=m;++pos)
					if(_k.s[pos])
					{
						flag=1;
						break;
					}
				if(!flag&&i==edi&&j==edj) ans+=lnum;
				continue;
			}
			if(west==2&&north==1)
			{
				_k.s[0]=_k.s[j]=0;
				zip_insert();
				continue;
			}
			if(west==1&&north==1)
			{
				int nm=1,pos=j+1;
				for(;pos<=m;++pos)
				{
					nm+=_k.s[pos]==1?1:(_k.s[pos]==2?-1:0);
					if(!nm) break;
				}
				_k.s[pos]=1;
				_k.s[0]=_k.s[j]=0;
				zip_insert();
				continue;
			}
			if(west==2&&north==2)
			{
				int nm=-1,pos=j-1;
				for(;pos;--pos)
				{
					nm+=_k.s[pos]==1?1:(_k.s[pos]==2?-1:0);
					if(!nm) break;
				}
				_k.s[pos]=2;
				_k.s[0]=_k.s[j]=0;
				zip_insert();
				continue;
			}
			
		}
	}
}

signed main()
{
	register char ch[20];
	read_(n),read_(m);
	for(int i=1;i<=n;++i)
	{
		scanf("%s",ch+1);
		for(int j=1;j<=m;++j)
			((ch[j]=='.'&&(mp[i][j]=1,edi=i,edj=j))||(mp[i][j]=0));
	}
	solve();
	cout<<ans<<'\n';
	
	return 0;
}

Posted by pitstop on Thu, 28 Oct 2021 04:32:21 -0700