HDU4026 Unlock the Cell Phone [状态压缩DP]

  一开始看范围特别小就写搜索了。。。结果自己随便出了个4*4就过不了了。。

  其实就是状态压缩DP,求哈密顿回路要多少条,只是要注意判断两点是否可以划线就可以了。

  

#include <stdio.h>
#include <string.h>
#include <algorithm>
typedef __int64 LL;
int n,m,tot;
int mz[25],bet[25][25][25],full;
int zero[16],zeros,hzero[25],lowb[65536];
LL d[16][65536],ans;
int cant(int st,int en,int stat){
    st=zero[st],en=zero[en];
    if(st>en)std::swap(st,en);
    for(int i=1;i<=bet[st][en][0];i++){
        int x=bet[st][en][i];
        if(mz[x]==1)return 1;
        if(mz[x]==0&&((stat>>hzero[x])&1)==0)return 1;
    }
    return 0;
}
LL dp(int last,int stat){
    if(d[last][stat]!=-1)return d[last][stat];
    if(stat==(stat&-stat))return 1;
    LL nans=0;
    int nstat=stat,now,i;
    while(nstat){
        now=(nstat&-nstat),i=lowb[now],nstat-=now;;
        if(i==last||cant(i,last,stat))continue;
        nans+=dp(i,stat&~(1<<last));
    }
    return d[last][stat]=nans;
}
int between(int k,int i,int j,int n,int m){
    int xk=k/m,yk=k%m,xi=i/m,yi=i%m,xj=j/m,yj=j%m;
    if((xk-xi)*(xk-xj)<=0&&(yk-yi)*(yk-yj)<=0){
        if((yj-yi)*(xk-xi)==(xj-xi)*(yk-yi))return 1;
    }
    return 0;
}
void init(int n,int m){
    for(int i=0;i<tot;i++){
        for(int j=i+1;j<tot;j++){
            int &x=bet[i][j][0];x=0;
            for(int k=i+1;k<j;k++){
                if(between(k,i,j,n,m))x++,bet[i][j][x]=k;
            }
        }
    }
    for(int i=0,x=1;i<16;i++,x<<=1)lowb[x]=i;
}
int main(){
  //  freopen("test.in","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF){
        ans=0,tot=n*m,zeros=0;
        init(n,m);
        for(int i=0;i<tot;i++){
            scanf("%d",&mz[i]);
            if(mz[i]==0)hzero[i]=zeros,zero[zeros++]=i;
        }
        full=(1<<zeros)-1;
        for(int i=0;i<zeros;i++)for(int j=0;j<=full;j++)d[i][j]=-1;
        for(int i=0;i<zeros;i++)ans+=dp(i,full);
        printf("%I64d\n",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/swm8023/p/2659375.html