P5074 Eat the Trees

思路

同样是插头DP,但是这题因为可以形成多个回路,所以左右括号是没有区别的,只需要01就可以表示了
注意if的嵌套关系
注意全零矩阵也要输出1

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int HASHsize = 400000;
int mat[20][20],n,m,T,pos[40];
int cnt[2],now,last,ans,endx,endy,fir[HASHsize+10],nxt[HASHsize+10],val[2][HASHsize+10],times[2][HASHsize+10];
void init(void){
    memset(mat,0,sizeof(mat));
    memset(cnt,0,sizeof(cnt));
    now=0,last=0,ans=0,endx=0,endy=0;
    memset(fir,0,sizeof(fir));
    memset(nxt,0,sizeof(nxt));
    memset(val,0,sizeof(val));
    memset(times,0,sizeof(times));
}
void insert(int c,int num){
    int t=c%HASHsize;
    for(int i=fir[t];i;i=nxt[i]){
        if(val[now][i]==c){
            times[now][i]+=num;
            return;
        }
    }
    ++cnt[now];
    val[now][cnt[now]]=c;
    times[now][cnt[now]]=num;
    nxt[cnt[now]]=fir[t];
    fir[t]=cnt[now];
}
void print(int x){
    for(int i=0;i<m+1;i++)
        printf("%lld",(x>>i)&1);
    printf("\n");
}
void dp(void){
    now=0;
    insert(0,1);
    for(int i=1;i<=n;i++){
        for(int k=1;k<=cnt[now];k++)
            val[now][k]<<=1;
        for(int j=1;j<=m;j++){
            last=now;
            now^=1;
            cnt[now]=0;
            memset(fir,0,sizeof(fir));
            memset(nxt,0,sizeof(nxt));
            // printf("i=%lld j=%lld\n",i,j);
            for(int k=1;k<=cnt[last];k++){
                int state=val[last][k],num=times[last][k],plugL=(state>>(j-1))&1,plugU=(state>>(j))&1;
                // printf("num=%lld\n",num);
                // print(state);
                // printf("plugL=%lld plugU=%lld\n",plugL,plugU);
                if(mat[i][j]){
                    //新建连通分量
                    if((!plugL)&&(!plugU)){
                        if(mat[i+1][j]&&mat[i][j+1])
                            insert(state+(1<<(j-1))+(1<<(j)),num);
                    }
                    //合并联通分量
                    else if(plugL&&plugU){
                        if(i==endx&&j==endy)
                            ans+=num;
                        else
                            insert(state-(1<<(j-1))-(1<<(j)),num);
                    }
                    //延续联通分量
                    else{
                        if(plugL){
                            // printf("!\n");
                            if(mat[i+1][j])
                                insert(state,num);
                            if(mat[i][j+1])
                                insert(state-(1<<(j-1))+(1<<(j)),num);
                        }
                        if(plugU){
                            if(mat[i+1][j])
                                insert(state-(1<<(j))+(1<<(j-1)),num);
                            if(mat[i][j+1])
                                insert(state,num);
                        }
                    }
                }
                else{
                    if((!plugL)&&(!plugU))
                        insert(state,num);
                }
            }
        }
    }
}
signed main(){
    scanf("%lld",&T);
    pos[0]=1;
    for(int i=1;i<30;i++)
        pos[i]=pos[i-1]<<1;
    while(T--){
        bool isok=true;
        init();
        scanf("%lld %lld",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                scanf("%lld",&mat[i][j]);
                if(mat[i][j]){
                    endx=i;endy=j;
                    isok=false;
                } 
            }
        // printf("endx=%lld endy=%lld\n",endx,endy);
        if(!isok){
            dp();
            printf("%lld\n",ans);
        }
        else{
            printf("1\n");
        }
    }
    return 0;
}
posted @ 2019-05-22 07:12  dreagonm  阅读(211)  评论(0编辑  收藏  举报