洛谷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 阅读(...) 评论(...) 编辑 收藏