洛谷P5074 Eat the Trees 题解
跟网络流建模题很像,注意到这题跟板子题有所不同,这一题可以有不止一个哈密顿回路,于是在更新最后答案时加一点判断即可
如果当前点是一个可以构成一个联通快的点,则判断当前点是不是最后一个可以放置的点,如果是更新答案;如果不是,则像普通操作一样更新下一个格子的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;
}