从上题的多环到这题的单环要考虑的东东多了, 插头也成了两种, 因此用到了三进制(即括号表示法中的'#','(',')'), 直接用三进制, 大量的除法和取余运算常数可能会大, 从而超时, 因此应该用4进制位运算会更好一些, 然后再存储状态方案数时再转三进制进行hash, 当然hash的方法还可以是别的复杂度不高的函数.
/********************************************************
** Author : Huikang Yih
** Email : huikangyi@gmail.com
** Date : 2014-11-29 16:37
** For : Ural 1519. Formula 1
*********************************************************/
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <cstring>
using namespace std;
typedef double DB;
typedef unsigned int UI;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef map<int, int> MPII;
typedef vector<int> VI;
typedef vector<bool> VB;
typedef vector<char> VC;
typedef vector<double> VD;
typedef vector<string> VS;
typedef vector<VI> VVI;
typedef vector<PII> VPII;
template <class T> inline bool checkMin(T& a, T b) { if (b < a) { a = b; return true; } return false; }
template <class T> inline bool checkMax(T& a, T b) { if (b > a) { a = b; return true; } return false; }
const int N = 15;
const int M = 2000005;
/*****************************************************************************************************/
struct mStack {
int top, arr[M];
inline void clear() { top = 0; }
inline void push(int x) { arr[top ++] = x; }
inline int pop() { return arr[-- top]; }
inline bool empty() { return !top; }
inline int size() { return top; }
}; // 自定义栈
/*****************************************************************************************************/
int n, m, nn, mm, g[N][N];
int pre, now;
mStack stk[2];
int visCount, vis[M]; // 访问标记
LL sum[2][M];
inline int mHash(int s) { // '四进制' 转 '三进制'
int ret = 0;
for (int i = 0, x = 1; i < m; i++, x *= 3) {
ret += (s & 3) * x;
s >>= 2;
}
return ret;
}
void update(int s, LL data) { // 更新函数
int x = mHash(s);
if (vis[x] != visCount) {
sum[now][x] = data;
vis[x] = visCount;
stk[now].push(s);
} else sum[now][x] += data;
}
inline LL solve() {
visCount = 0;
memset(vis, -1, sizeof(vis));
stk[pre = 1].clear();
stk[now = 0].clear(); // 初始化
update(0, 1); // 初始边界量
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
pre ^= 1, now ^= 1; visCount ++; // 滚动数组及栈(或队列)
if (stk[pre].empty()) return 0LL; // 无解, 提前退出
while (!stk[pre].empty()) {
int s = stk[pre].pop();
long long data = sum[pre][mHash(s)];
if (j == 1) {
if (s & (1 << (m << 1))) continue;
s <<= 2;
} // 首列
int left = s >> ((j - 1) << 1) & 3;
int up = s >> (j << 1) & 3;
int s0 = s ^ (left << ((j - 1) << 1)) ^ (up << (j << 1)); // 特征插头值
if (!g[i][j]) {
if (!left && !up) update(s0, data);
continue;
} // 障碍格子
if (!left && !up) {
if (g[i][j + 1] && g[i + 1][j]) update(s0 | (9 << ((j - 1) << 1)), data);
continue;
} // 新生插头
if ((!left) ^ (!up)) {
if (g[i + 1][j]) update(s0 | ((left | up) << ((j - 1) << 1)), data);
if (g[i][j + 1]) update(s0 | ((left | up) << (j << 1)), data);
continue;
} // 维持插头原态
if (left == 1 && up == 2) {
if (i == nn && j == mm) update(s0, data);
continue;
} // 并列12插头
if (left == 2 && up == 1) {
update(s0, data);
continue;
} // 并列21插头
if (left == 1 && up == 1) {
int cnt = 1, idx = j;
while (cnt > 0) {
idx ++;
int w = s >> ((idx) << 1) & 3;
if (w == 1) cnt ++;
if (w == 2) cnt --;
}
update(s0 ^ (3 << (idx << 1)), data);
continue;
} // 并列11插头
if (left == 2 && up == 2) {
int cnt = 1, idx = j - 1;
while (cnt > 0) {
idx --;
int w = s >> (idx << 1) & 3;
if (w == 1) cnt --;
if (w == 2) cnt ++;
}
update(s0 ^ (3 << (idx << 1)), data);
continue;
} // 并列22插头
cout << "error happens." << endl; // 如果执行了此语句, 则说明四进制编码有错
}
if (i == nn && j == mm) return sum[now][0]; // 最后一个非障碍格子
}
}
return -1; // 出错, nn, mm不对返回-1
}
int main() {
scanf("%d%d", &n, &m);
memset(g, 0, sizeof(g));
int xxx = 0; for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
char x = getchar();
while (x != '.' && x != '*') x = getchar();
if (x == '.') {
g[i][j] = true;
nn = i; mm = j;
xxx ++;
}
}
}
if (xxx & 1) printf("0\n");
else printf("%I64d\n", solve());
return 0;
}
本文深入探讨了在解决特定问题时如何将四进制编码转换为三进制编码,并利用滚动数组和栈数据结构优化算法效率。详细解释了如何通过位操作和哈希函数来简化复杂度,特别是在处理多环到单环转变时的策略。
1万+

被折叠的 条评论
为什么被折叠?



