Ural 1519 Formula --插头DP

题目地址:点击打开链接


【题目大意】

    一个N*M的方格,有一些点不能访问,求汉密尔顿回路条数


【分析】

    裸的插头DP,我代码中是用的括号表示法,而且用排序代替了Hash,这样速度比较快。


【代码】

/*************************
    ID:Ciocio
    LANG:C++
    DATE:2014-1-27
    TASK:Ural 1519
*************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define MAXN 12
#define MAXSTATE 300000

typedef long long LL;
int N,M,lasti,lastj;
bool mat[MAXN+10][MAXN+10];
int sc,SC;
int s_[MAXSTATE+10],S_[MAXSTATE+10];
LL f_[MAXSTATE+10],F_[MAXSTATE+10];
int* s=s_;
int* S=S_;
LL* f=f_;
LL* F=F_;

char _read(){
    char tt=getchar();
    while(tt!='*'&&tt!='.') tt=getchar();
    return tt;
}

void _qsort(int l,int r){
    int i=l,j=r,m=S[(l+r)>>1];
    while(i<=j){
        while(S[i]<m) i++;
        while(S[j]>m) j--;
        if(i<=j){
            swap(S[i],S[j]);
            swap(F[i],F[j]);
            i++;j--;
        }
    }
    if(l<j) _qsort(l,j);
    if(i<r) _qsort(i,r);
}

void _init(){
    cin>>N>>M;
    for(int i=0;i<N;i++)
        for(int j=0;j<M;j++){
            if(_read()=='*')
                mat[i][j]=true;
            else{
                lasti=i;
                lastj=j;
            }
        } 
}

int replace(int state,int j,int n){
    return (state^(((state>>(j<<1))&3)<<(j<<1)))|(n<<(j<<1));
}

int getp(int state,int j){
    return (state>>(j<<1))&3;
}

int getl(int state,int j){
    return getp(state,j);
}

int getu(int state,int j){
    return getp(state,j+1);
}

int replacedr(int state,int j,int n1,int n2){
    return replace(replace(state,j,n1),j+1,n2);
}

void getcl(int state,int j,int& ns){
    ns=replacedr(state,j,0,0);
    int get=1;
    for(int i=j+2;i<=M;i++){
        if(getp(ns,i)==1) get++;
        else if(getp(ns,i)==2) get--;
        if(!get){
            ns=replace(ns,i,1);
            break;
        }
    }
}

void getcr(int state,int j,int& ns){
    ns=replacedr(state,j,0,0);
    int get=1;
    for(int i=j-1;i>=0;i--){
        if(getp(ns,i)==2) get++;
        else if(getp(ns,i)==1) get--;
        if(!get){
            ns=replace(ns,i,2);
            break;
        }
    }
}

void _solve(){
    LL ans=0;
    S[SC]=0;
    F[SC++]=1;
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
            swap(s,S);
            swap(f,F);
            sc=SC;SC=0;
            if(mat[i][j]){
                for(int si=0;si<sc;si++){
                    int l=getl(s[si],j);
                    int u=getu(s[si],j);
                    if(!(l|u)){
                        S[SC]=s[si];
                        F[SC++]=f[si];
                    }
                }
            }
            else{
                for(int si=0;si<sc;si++){
                    int l=getl(s[si],j);
                    int u=getu(s[si],j);
                    if(l&&u){
                        int ns;
                        if(l==2&&u==1) ns=replacedr(s[si],j,0,0);
                        else if(l==1&&u==1) getcl(s[si],j,ns);
                        else if(l==2&&u==2) getcr(s[si],j,ns);
                        else{
                            if((!replacedr(s[si],j,0,0))&&i==lasti&&j==lastj) ans+=f[si];
                            continue;
                        }
                        S[SC]=ns;
                        F[SC++]=f[si];
                    }
                    else if(l||u){
                        int ns;
                        ns=replacedr(s[si],j,l,u);
                        S[SC]=ns;
                        F[SC++]=f[si];
                        ns=replacedr(s[si],j,u,l);
                        S[SC]=ns;
                        F[SC++]=f[si];
                    }
                    else{
                        int ns;
                        ns=replacedr(s[si],j,1,2);
                        S[SC]=ns;
                        F[SC++]=f[si];
                    }
                }
            }
            _qsort(0,SC-1);
            int RSC=0,ii=0;
            while(ii<SC){
                int jj=ii+1;
                while(jj<SC&&S[ii]==S[jj]) F[ii]+=F[jj++];
                S[RSC]=S[ii];
                F[RSC++]=F[ii];
                ii=jj;
            }
            SC=RSC;
        }
        int RSC=0,ii=0;
        while(ii<SC){
            while(ii<SC&&getp(S[ii],M)) ii++;
            if(ii<SC){
                S[RSC]=S[ii]<<2;
                F[RSC++]=F[ii++];
            }
        }
        SC=RSC;
    }
    cout<<ans<<endl;
}

int main(){
    _init();
    _solve();
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值