题目大意:

给定一个图,一部分点'*'作为障碍物,求经过所有非障碍点的汉密尔顿回路有多少条

 

基础的插头DP题目,对于陈丹琦的论文来说我觉得http://blog.sina.com.cn/s/blog_51cea4040100gmky.html

这个博客写的更容易理解,不过好像这篇博客里的代码有问题,反正是A不了题目的

不过上面的图和思路写的很清楚,可以作为参考

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
#define ll unsigned long long
const int HASH_SIZE = 199917;

bool mp[15][15];
char str[15][15];
int n, m , k , nn , mm;
int tot[2] , bit[15] , hash[HASH_SIZE] , state[2][HASH_SIZE];
ll dp[2][HASH_SIZE] , ans;

void init()
{
    //每一位用4进制保存,那么对于每一个状态来说都是右移2次,所以这里i*2
    for(int i=0 ; i<=13 ; i++) bit[i] = i<<1;
    memset(dp , 0 , sizeof(dp));
    tot[0] = dp[0][1] = 1 , ans = k = 0;
    state[0][1] = 0;
}

void hash_in(int s , ll sum)//s表示当前状态,sum是指s状态下共有sum种方式形成
{
   // print(s);
   // cout<<" "<<sum<<endl;
    int p = s%HASH_SIZE;
    while(hash[p]){
        if(state[k][hash[p]] == s){
            dp[k][hash[p]] += sum;
            return ;
        }
        p++;
        if(p == HASH_SIZE) p=0;
    }
    hash[p] = ++tot[k];
    state[k][hash[p]] = s;
    dp[k][hash[p]] = sum;
}

void work()
{
    for(int i=1 ; i<=n ; i++){
        for(int j=1 ; j<=m ; j++){
            k^=1 ; //滚动数组
            tot[k] = 0;
            memset(hash , 0 , sizeof(hash));
            for(int u=1 ; u<=tot[1-k] ; u++){
                int s = state[1-k][u] , curs;
                ll sum = dp[1-k][u];
                int p = (s>>bit[j-1])&3 , q = (s>>bit[j])&3; //3进制 , 用( , # , )来理解
                if(!mp[i][j]){
                    if(p==0 && q==0) hash_in(s , sum);
                }
                else{
                    if(p == 0 && q == 0){
                        if(!mp[i+1][j] || !mp[i][j+1]) continue;
                        curs = s + (1<<bit[j-1]) + (2<<bit[j]);
                        hash_in(curs , sum);
                    }
                    else if(!p && q){
                        if(mp[i][j+1]) hash_in(s , sum);
                        if(mp[i+1][j]){
                            curs = s+q*(1<<bit[j-1])-q*(1<<bit[j]);
                            hash_in(curs , sum);
                        }
                    }
                    else if(p && !q){
                        if(mp[i+1][j]) hash_in(s , sum);
                        if(mp[i][j+1]){
                            curs = s - p*(1<<bit[j-1])+p*(1<<bit[j]);
                            hash_in(curs , sum);
                        }
                    }
                    else if(p+q==2){ //可理解为p==1 && q==1
                        int cnt = 1;
                        for(int v=j+1 ; v<=m ; v++){
                            int w = (s>>bit[v])&3;
                            if(w == 1) cnt++;
                            if(w == 2) cnt--;
                            if(!cnt){
                                curs = s-(1<<bit[v]); //将)转化为( ->状态由2->1 , 减少了一个
                                break;
                            }
                        }
                        curs = curs-(1<<bit[j])-(1<<bit[j-1]);
                        hash_in(curs , sum);
                    }
                    else if(p+q==4){//可理解为p==2 && q==2
                        int cnt = 1;
                        for(int v=j-2 ; v>=1 ; v--){
                            int w = (s>>bit[v])&3;
                            if(w == 1) cnt--;
                            if(w == 2) cnt++;
                            if(!cnt){
                                curs= s+(1<<bit[v]);
                                break;
                            }
                        }
                        curs = curs-(2<<bit[j])-(2<<bit[j-1]);
                        hash_in(curs , sum);
                    }
                    else if(p==1 && q==2){
                        if(i==nn && j==mm)
                            ans+=sum;
                    }
                    else if(p==2 && q==1){
                        curs = s-(2<<bit[j-1])-(1<<bit[j]);
                        hash_in(curs , sum);
                    }
                }
            }
        }
        for(int j=1 ; j<=tot[k] ; j++) state[k][j]<<=2;
    }
    printf("%lld\n" , ans);
}

int main()
{
   // freopen("in.txt" , "r" , stdin);
    while(~scanf("%d%d" , &n , &m))
    {
        memset(mp , 0 , sizeof(mp));
        for(int i=1 ; i<=n ; i++){
            scanf("%s" , str[i]+1);
            for(int j=1 ; j<=m ; j++){
                mp[i][j] = str[i][j]=='.';
               // if(mp[i][j]) cout<<i<<" "<<j<<endl;
                if(mp[i][j]) nn=i , mm=j;//记录最后一个可执行块
            }
        }
        init();
        work();
    }
    return 0;
}
View Code

 

后来写hdu上的题目的时候觉得kuangbin的表达方式还是很清晰的,所以又将源代码修改成了:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 
  6 using namespace std;
  7 #define ll unsigned long long
  8 const int HASH = 10007;
  9 const int STATE = 1000010;
 10 const int MAXD = 15;
 11 int  n , m , enx , eny;
 12 int code[MAXD] , mp[MAXD][MAXD];
 13 ll ans = 0;
 14 
 15 struct HASHMAP{
 16     int head[HASH] , next[STATE] , state[STATE] , size;
 17     ll f[STATE];
 18 
 19     void init(){
 20         size = 0;
 21         memset(head , -1 , sizeof(head));
 22     }
 23 
 24     void push_in(int st , ll sum){
 25         int h = st%HASH;
 26         for(int i = head[h] ; ~i ; i=next[i]){
 27             if(st == state[i]){
 28                 f[i]+=sum;
 29                 return ;
 30             }
 31         }
 32         f[size]=sum;
 33         state[size] = st;
 34         next[size] = head[h];
 35         head[h] = size++;
 36     }
 37 }hashmap[2];
 38 
 39 void decode(int *code , int m , int st)
 40 {
 41     for(int i=m ; i>=0 ; i--){
 42         code[i] = st&3;
 43         st>>=2;
 44     }
 45 }
 46 
 47 int encode(int *code , int m)
 48 {
 49     int st=0;
 50     for(int i=0 ; i<=m ; i++){
 51         st<<=2;
 52         st |= code[i];
 53     }
 54     return st;
 55 }
 56 
 57 void init()
 58 {
 59     char str[MAXD][MAXD];
 60     for(int i=1 ; i<=n ; i++){
 61         scanf("%s" , str[i]+1);
 62         for(int j=1 ; j<=m ; j++){
 63             if(str[i][j] == '.'){
 64                 mp[i][j] = 1;
 65                 enx = i , eny = j;
 66             }else mp[i][j] = 0;
 67         }
 68         mp[i][m+1]=0;
 69         mp[n+1][i] = 0;
 70     }
 71 }
 72 
 73 void shift(int *code , int m) //换行,可理解为将最右侧轮廓线换到了下一行的最左侧
 74 {
 75     for(int i=m ; i>=0 ; i--) code[i] = code[i-1];
 76     code[0] = 0;
 77 }
 78 
 79 void dpblank(int i , int j , int cur) //处理可执行格子
 80 {
 81    // cout<<"ok: "<<i<<" "<<j<<endl;
 82     int k , left , up;
 83     for(k=0 ; k<hashmap[cur].size ; k++){
 84         decode(code , m , hashmap[cur].state[k]);
 85         left = code[j-1];
 86         up = code[j];
 87         if(!left && !up){
 88             if(!mp[i][j+1] || !mp[i+1][j]) continue;
 89             code[j-1] = 1 , code[j] = 2;
 90             hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
 91         }
 92         else if(!left && up){
 93             if(mp[i][j+1]) hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
 94             if(mp[i+1][j]){
 95                 code[j-1] = up , code[j] = 0;
 96                 if(j == m) shift(code , m);
 97                 hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
 98             }
 99         }
100         else if(left && !up){
101             if(mp[i+1][j]){
102                 if(j == m)  shift(code , m);
103                 hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
104             }
105             if(mp[i][j+1]){
106                 code[j-1] = 0 , code[j] = left;
107                 hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
108             }
109         }
110         else if(left==1 && up == 1){
111             int cnt = 1;
112             for(int v=j+1 ; v<=m ; v++){
113                 if(code[v]==1)cnt++;
114                 if(code[v]==2)cnt--;
115                 if(!cnt){
116                     code[v]=1;
117                     break;
118                 }
119             }
120             code[j-1] = code[j] = 0;
121             if(j == m) shift(code , m);
122             hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
123         }
124         else if(left == 2 && up == 2){
125             int cnt=1;
126             for(int v=j-2 ; v>=1 ; v--){
127                 if(code[v]==2)cnt++;
128                 if(code[v]==1)cnt--;
129                 if(!cnt){
130                     code[v]=2;
131                     break;
132                 }
133             }
134             code[j-1] = code[j] = 0;
135             if(j == m) shift(code , m);
136             hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
137         }
138         else if(left==1 && up==2){
139             if(i==enx && j==eny) ans+=hashmap[cur].f[k];
140         }
141         else{
142             code[j-1]=code[j]=0;
143             if(j == m) shift(code , m);
144             hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
145         }
146     }
147 }
148 
149 void dpblock(int i , int j , int cur)
150 {
151    // cout<<"flase: "<<i<<" "<<j<<endl;
152     int k , left , up;
153     for(k=0 ; k<hashmap[cur].size ; k++){
154         decode(code , m , hashmap[cur].state[k]);
155         left = code[j-1] , up = code[j];
156         if(!left && !up){
157             if(j == m) shift(code , m);
158             hashmap[cur^1].push_in(encode(code , m) , hashmap[cur].f[k]);
159         }
160     }
161 }
162 
163 ll solve()
164 {
165     ans = 0;
166     int cur = 0;
167     hashmap[cur].init();
168     hashmap[cur].push_in(0 , 1);
169     for(int i=1 ; i<=n ; i++){
170         for(int j=1 ; j<=m ; j++){
171             hashmap[cur^1].init();
172             if(mp[i][j]) dpblank(i , j , cur);
173             else dpblock(i , j , cur);
174             cur ^= 1;
175         }
176     }
177     return ans;
178 }
179 
180 int main()
181 {
182   //  freopen("in.txt" , "r" , stdin);
183     while(~scanf("%d%d" , &n , &m))
184     {
185         init();
186         printf("%I64d\n" , solve());
187     }
188     return 0;
189 }
View Code

 

 posted on 2015-08-10 16:05  Love风吟  阅读(268)  评论(0编辑  收藏  举报