洛谷P5074 Eat the Trees 题解

插头dp

跟网络流建模题很像,注意到这题跟板子题有所不同,这一题可以有不止一个哈密顿回路,于是在更新最后答案时加一点判断即可

如果当前点是一个可以构成一个联通快的点,则判断当前点是不是最后一个可以放置的点,如果是更新答案;如果不是,则像普通操作一样更新下一个格子的dp值即可
代码:

#include<bits/stdc++.h>
#define int long long
#define INF 2147483647
#define mem(i,j) memset(i,j,sizeof(i))
#define F(i,j,n) for(register int i=j;i<=n;i++)
#define Hashmod 299993
using namespace std;
struct hahaha{
	int _s[20];
};
struct Hash{
	int sta[2],num[2],nxt;
}s[300010];
int n,m,head[300010],cnt[2],mp[20][20],edi,edj,now,lst,ans=0,T;
char ch[20];
inline int read(){
	int datta=0;char chchc=getchar();bool okoko=0;
	while(chchc<'0'||chchc>'9'){if(chchc=='-')okoko=1;chchc=getchar();}
	while(chchc>='0'&&chchc<='9'){datta=datta*10+chchc-'0';chchc=getchar();}
	return okoko?-datta:datta;
}
inline void ins(int sta,int num){
	int tmp=sta%Hashmod;
	for(int i=head[tmp];i;i=s[i].nxt)
		if(sta==s[i].sta[now]){
			s[i].num[now]+=num;
			return ;
		}
	s[++cnt[now]].sta[now]=sta;
	s[cnt[now]].num[now]=num;
	s[cnt[now]].nxt=head[tmp];
	head[tmp]=cnt[now];
}
inline hahaha unpack(int sta){
	hahaha rt;
	rt._s[0]=sta&3;
	F(i,1,m)
		rt._s[i]=(sta>>(i<<1))&3;
	return rt;
}
inline int WinRAR(hahaha rt){
	int sta=0;
	F(i,1,m)
		sta=sta|(rt._s[i]<<(i<<1));
	sta|=rt._s[0];
	return sta;
}
inline void solve(){
	ins(0,1);
	F(i,1,n){
		F(j,1,m){
			lst=now;
			now^=1;
			cnt[now]=0;
			mem(head,0);
			F(k,1,cnt[lst]){
				hahaha now_pnt=unpack(s[k].sta[lst]),_k=now_pnt;
				int lnum=s[k].num[lst],west=now_pnt._s[0],north=now_pnt._s[j];
				if(!mp[i][j]){
					if(!west&&!north)
						ins(WinRAR(_k),lnum);
					goto ctn;
				}
				if(!west&&!north){
					if(mp[i+1][j]&&mp[i][j+1]){
						_k._s[0]=2;
						_k._s[j]=1;
						ins(WinRAR(_k),lnum);
						_k=now_pnt;
					}
					goto ctn;
				}
				if(!west&&north){
					if(mp[i+1][j])
						ins(WinRAR(_k),lnum);
					if(mp[i][j+1]){
						_k._s[0]=north;
						_k._s[j]=0;
						ins(WinRAR(_k),lnum);
						_k=now_pnt;
					}
					goto ctn;
				}
				if(west&&!north){
					if(mp[i][j+1])
						ins(WinRAR(_k),lnum);
					if(mp[i+1][j]){
						_k._s[0]=0;
						_k._s[j]=west;
						ins(WinRAR(_k),lnum);
						_k=now_pnt;
					}
					goto ctn;
				}
				if(west==2&&north==1){
					_k._s[0]=_k._s[j]=0;
					ins(WinRAR(_k),lnum);
					_k=now_pnt;
					goto ctn;
				}
				if(west==1&&north==1){
					int nm=1,pos;
					for(pos=j+1;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;
					ins(WinRAR(_k),lnum);
					_k=now_pnt;
					goto ctn;
				}
				if(west==2&&north==2){
					int nm=-1,pos;
					for(pos=j-1;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;
					ins(WinRAR(_k),lnum);
					_k=now_pnt;
					goto ctn;
				}
				if(west==1&&north==2){
					if(i==edi&&j==edj)
						ans+=lnum;
					else
						_k._s[0]=_k._s[j]=0,ins(WinRAR(_k),lnum),_k=now_pnt;
				}
				ctn:;
			}
		}
	}
}
signed main(){
	T=read();
    int _T=T;
	while(T--){
		n=read();m=read();
		mem(s,0);mem(head,0);mem(cnt,0);mem(mp,0);ans=0;
		F(i,1,n){
			F(j,1,m){
				mp[i][j]=read();
                if(mp[i][j]==1)
                    edi=i,edj=j;
            }
		}
		now=lst=0;
		solve();
		printf("Case %lld: There are %lld ways to eat the trees.\n",_T-T,ans);
	}
	return 0;
}
posted @ 2019-02-27 19:48  hzf29721  阅读(221)  评论(0编辑  收藏  举报