题目大意:给出一张图,要求从左下角走到右下角,且所有的非障碍点都走一次,问有多少种方法
解题思路:在后面加上两行就可以当成单回路插头DP了
比如
…
…
.#.
后面加上两行后,就变成了饿
…
…
.#.
.#.
…
加的后面的两行只有一条路径
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 10
#define S1 14000
#define S2 1600000
struct Queue{
int opt;
long long sum;
}Q[2][S1];
char g[N][N];
int cnt[2], now, state[2][S2];
int pow3[N];
int n, m;
int get(int opt, int col) {
return opt / pow3[col] % 3;
}
int set(int opt, int col, int value) {
return opt + (value - get(opt, col)) * pow3[col];
}
int change1(int opt, int col) {
for (int flag = 0; col < m; col++) {
int tmp = get(opt, col);
if (tmp == 1)
flag++;
else if (tmp == 2)
flag--;
if (!flag)
return set(opt, col, 1);
}
return -1;
}
int change2(int opt, int col) {
for (int flag = 0; col >= 0; col--) {
int tmp = get(opt, col);
if (tmp == 2)
flag++;
else if (tmp == 1)
flag--;
if (!flag)
return set(opt, col, 2);
}
return -1;
}
void enqueue(int opt, int col, long long sum) {
if (col == m - 1 && get(opt, m))
return ;
int &id = state[now][opt];
if (id)
Q[now][id].sum += sum;
else {
id = ++cnt[now];
Q[now][id].opt = opt;
Q[now][id].sum = sum;
}
}
void init() {
for (int i = 0; i < n; i++)
scanf("%s", g[i]);
for (int i = 0; i < m; i++)
if (i == 0 || i == m - 1)
g[n][i] = '.';
else
g[n][i] = '#';
n++;
for (int i = 0; i < m; i++)
g[n][i] = '.';
n++;
for (int k = 1, l = cnt[0]; k <= l; k++)
state[0][Q[0][k].opt] = 0;
for (int k = 1, l = cnt[1]; k <= l; k++)
state[1][Q[1][k].opt] = 0;
cnt[0] = cnt[1] = 0;
}
void solve() {
enqueue(0, 0, 1);
now ^= 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
for (int k = 1, l = cnt[now ^ 1]; k <= l; k++) {
int opt = Q[now ^ 1][k].opt;
long long sum = Q[now ^ 1][k].sum;
int left = get(opt, m), up = get(opt, j);
if (g[i][j] == '#') {
if (!left && !up)
enqueue(opt, j, sum);
continue;
}
if (!left && !up) {
enqueue(set(set(opt, j, 1), m, 2), j, sum);
}
else if (!left || !up) {
enqueue(set(set(opt, j, 0), m, left + up), j, sum);
enqueue(set(set(opt, m, 0), j, left + up), j, sum);
}
else if (left == 1 && up == 1) {
int tmp = change1(opt, j);
enqueue(set(set(tmp, j, 0), m, 0), j, sum);
}
else if (left == 2 && up == 2) {
int tmp = change2(opt, j);
enqueue(set(set(tmp, j, 0), m, 0), j, sum);
}
else if (left == 1 && up == 2) {
if(i == n - 1 && j == m - 1)
enqueue(set(set(opt, j, 0), m, 0), j, sum);
}
else if(left == 2 && up == 1) {
enqueue(set(set(opt, j, 0), m, 0), j, sum);
}
}
now ^= 1;
for(int k = 1, l = cnt[now]; k <= l; k++)
state[now][Q[now][k].opt] = 0;
cnt[now] = 0;
}
}
now ^= 1;
printf("%lld\n", Q[now][state[now][0]].sum);
}
int main() {
pow3[0] = 1;
for(int i = 1; i < N; i++)
pow3[i] = pow3[i - 1] * 3;
while(scanf("%d%d", &n, &m) != EOF && n + m) {
init();
solve();
}
return 0;
}