Ural1519Formula 1

从上题的多环到这题的单环要考虑的东东多了, 插头也成了两种, 因此用到了三进制(即括号表示法中的'#','(',')'), 直接用三进制, 大量的除法和取余运算常数可能会大, 从而超时, 因此应该用4进制位运算会更好一些, 然后再存储状态方案数时再转三进制进行hash, 当然hash的方法还可以是别的复杂度不高的函数.

/********************************************************
** Author 	: Huikang Yih
** Email	: [email protected] 
** 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;
}


你可能感兴趣的:(Ural1519Formula 1)