URAL 1519 Formula 1

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1519

陈丹琦的《基于连通性状态压缩的动态规划问题》的论文上的题目

题意:

给你m*n的棋盘,有的格子是障碍,问共有多少条回路使得经过每个非障碍格子恰好一次。

做法:

论文上的思路讲的很清楚了,这里用最小表示法来做。

因为(2 ≤ NM ≤ 12),所以最多出现6个联通块,所以用8进制来做。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 int N, M;
  4 #define maxn 15
  5 #define HASH 30007
  6 #define STATE 200010
  7 int mp[maxn][maxn];
  8 int pos[maxn];
  9 int mark, ex, ey;
 10 int code[maxn];
 11 struct HashMap
 12 {
 13     int head[HASH], next[STATE], cnt;
 14     long long state[STATE];
 15     long long sum[STATE];
 16     void init()
 17     {
 18         cnt = 0;
 19         memset(head, -1, sizeof(head));
 20     }
 21     void push(long long sta, long long val)
 22     {
 23         int h = sta%HASH;
 24         for(int i = head[h]; i != -1; i = next[i])
 25         {
 26             if(state[i] == sta)  //如果这种状态已经存在
 27             {
 28                 sum[i] += val;
 29                 return;
 30             }
 31         }
 32         state[cnt] = sta;
 33         sum[cnt] = val;
 34         next[cnt] = head[h];
 35         head[h] = cnt++;
 36     }
 37 }hashmp[2];//滚动数组
 38 void decode(int *code, long long sta)  
 39 {
 40     for(int i = M; i >= 0; i--)
 41     {
 42         code[i] = sta&7;
 43         sta >>= 3;
 44     }
 45 }
 46 long long encode(int *code) //转化成2进制
 47 {
 48     int cnt = 1;
 49     int vis[maxn];
 50     memset(vis, -1, sizeof(vis));
 51     vis[0] = 0;  //0不连通
 52     long long sta = 0;
 53     
 54     for(int i = 0; i <= M; i++)
 55     {
 56         if(vis[code[i]] == -1) vis[code[i]] = cnt++;
 57         code[i] = vis[code[i]];
 58         sta <<= 3;
 59         sta |= code[i];
 60     }
 61     return sta;
 62 }
 63 void AtLast(int *code)
 64 {
 65     for(int i = M; i > 0; i--) code[i] = code[i-1];
 66     code[0] = 0;
 67 }
 68 void slove()
 69 {
 70     mark = 0;
 71     hashmp[mark].init();
 72     hashmp[mark].push(0, 1);       //开始时轮廓线在最上方
 73 
 74     for(int i = 1; i <= N; i++)
 75     {
 76         for(int j = 1; j <= M; j++)
 77         {
 78             hashmp[mark^1].init();//初始化
 79             if(mp[i][j] == 0)     //不能放置
 80             {
 81                 for(int k = 0; k < hashmp[mark].cnt; k++)
 82                 {
 83                     decode(code, hashmp[mark].state[k]);
 84                     code[j-1] = code[j] = 0;
 85                     if(j == M) AtLast(code);
 86                     hashmp[mark^1].push(encode(code),hashmp[mark].sum[k]);
 87                 }
 88             }
 89             else                //可以放置
 90             {
 91                 for(int k = 0; k < hashmp[mark].cnt; k++)
 92                 {
 93                     decode(code, hashmp[mark].state[k]);
 94                     int left, up;
 95                     left = code[j-1]; up = code[j];
 96                     if(left == 0 && up == 0)            //情况1:没有上插头和左插头,新建一个联通分量  
 97                     {
 98                         if(mp[i+1][j] && mp[i][j+1])
 99                         {
100                             code[j-1] = code[j] = 13;  //如果mp[i][j+1] = 1,则不可能出现j == M的情况
101                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
102                         }
103                     }
104                     else if(left && up)                //情况2:有上插头和左插头
105                     {
106                         if(left != up)                 //上插头和左插头不联通,合并联通分量。
107                         {
108                             code[j-1] = code[j] = 0;   //则不可能再有右插头和下插头
109                             for(int ii = 0; ii <= M; ii++)
110                             {
111                                 if(code[ii] == up) code[ii] = left;
112                             }
113                             if(j == M) AtLast(code);
114                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
115                         }
116                         else if(left == up)            //上插头和左插头联通
117                         {
118  
119                             if(i == ex && j == ey)     //这种情况只可能出现在最后一个可以摆放的位置
120                             {
121                                 code[j-1] = code[j] = 0;
122                                 if(j == M) AtLast(code);
123                                 hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
124                             }
125                         }
126                     }
127                     else if((left&&(!up)) || (up&&(!left)))//情况3:上插头和左插头只存在一个
128                     {
129                         int val;
130                         if(left) val = left;
131                         else val = up;
132                         if(mp[i][j+1])     //右边的格子可走
133                         {
134                             code[j] = val; code[j-1] = 0;
135                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
136                         }
137                         if(mp[i+1][j])    //下面的格子可走
138                         {
139                             code[j-1] = val; code[j] = 0;
140                             if(j == M) AtLast(code);
141                             hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]);
142                         }                        
143                     }
144                 }
145             }
146             mark^=1; 
147         }
148     }
149 }
150 int main() 
151 {
152    // freopen("in.txt", "r", stdin);
153    //  freopen("out.txt", "w", stdout);
154     while(~scanf("%d%d", &N, &M))
155     {
156         memset(mp, 0, sizeof(mp));
157         bool flag = false;
158         for(int i = 1; i <= N; i++)
159         {
160             char str[15];
161             scanf("%s", str);
162             for(int j = 0; j < M; j++)
163             {
164                 if(str[j] == '.')
165                 {
166                     mp[i][j+1] = 1;
167                     ex = i; ey = j+1;
168                     flag = true;       
169                 }   
170                 else if(str[j] == '*') mp[i][j+1] = 0;
171             }
172         }
173         if(flag == false)  //没有空块
174         {
175             printf("0
"); continue;
176         }
177         slove();
178         long long ans = 0;;
179         for(int i = 0; i < hashmp[mark].cnt; i++)
180         {
181             ans += hashmp[mark].sum[i];
182         }
183         printf("%lld
", ans);
184     }
185     return 0;
186 }
原文地址:https://www.cnblogs.com/titicia/p/4902481.html