[POJ3133]Manhattan Wiring 插头dp
原题POJ3133
题意:N*M有障碍矩阵,0可通过,1为障碍,两个2,两个3,求连接两个2和连接两个3的两条不相交路径长度和的最小值(1 <= N, M <= 9).
//——————————————————————–
插头dp
由于路径起点和终点确定,只需要记录插头对应的起点,不需要插头记录连通性。
标号0无插头,1不知起点的插头,2,3分别对应起点为2,3的插头。
***1.对2或者3的格子
(1)没有左,上插头,可增加右插头或下插头,标号与格子的值相同。
(2)只有左插头或只有上插头,并且标号等于格子的值,此格为终点没有右,下插头。
(3)有左,上插头,不合法。
***2.对0的格子
(1)没有左,上插头,可增加右,下插头,标号为2或3,也可跳过此格不放。
(2)只有左插头或只有上插头,延伸插头至右插头或下插头,保持标号不变。
(3)有左,上插头,只有插头标号相同,合并左上插头。
***3.对1的格子
由于不能放,只有没有左,上插头的情况可以转移。
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 15
#define inf 0x7f7f7f7f
#define mod 1000000007
#define HASH 10007
#define STATE 1000100
typedef long long ll;
int n, m;
int code[N];
int mp[N][N];
struct HASHMAP
{
int head[HASH], next[STATE], size;
int f[STATE], state[STATE];
void init() {
size = 0;
memset(head, -1, sizeof(head));
}
void push(int st, int ans) {
int h = st % HASH;
for (int i = head[h]; i != -1; i = next[i]) {
if (state[i] == st) {
f[i] = min(f[i], ans);
return;
}
}
state[size] = st;
f[size] = ans;
next[size] = head[h];
head[h] = size++;
}
}hm[2];
void decode(int st)
{
for (int i = m; i >= 0; i--) {
code[i] = st & 3;
st >>= 2;
}
}
int encode()
{
int st = 0;
for (int i = 0; i <= m; i++) {
st <<= 2;
st |= code[i];
}
return st;
}
void shift()
{
for (int i = m; i > 0; i--) {
code[i] = code[i-1];
}
code[0] = 0;
}
void dpblank(int r, int c, int cur)
{
for (int k = 0; k < hm[cur].size; k++) {
decode(hm[cur].state[k]);
int up = code[c];
int left = code[c-1];
if (mp[r][c] == 2 || mp[r][c] == 3) {
if ((up == mp[r][c] && !left) || (!up && left == mp[r][c])) {
code[c] = code[c-1] = 0;
if (c == m) shift();
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
if (!up && !left) {
if (mp[r][c+1] == 1 || mp[r][c+1] == mp[r][c]) {
code[c] = mp[r][c];
code[c-1] = 0;
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
if (mp[r+1][c] == 1 || mp[r+1][c] == mp[r][c]) {
code[c-1] = mp[r][c];
code[c] = 0;
if (c == m) shift();
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
}
continue;
}
if (up && left) {
if (up == left) {
code[c] = code[c-1] = 0;
if (c == m) shift();
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
}
else if (up || left) {
int t = up | left;
if (mp[r][c+1] == 1 || mp[r][c+1] == t) {
code[c] = t;
code[c-1] = 0;
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
if (mp[r+1][c] == 1 || mp[r+1][c] == t) {
code[c-1] = t;
code[c] = 0;
if (c == m) shift();
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
}
else {
code[c] = code[c-1] = 0;
if (c == m) shift();
hm[cur^1].push(encode(), hm[cur].f[k]);
for (int i = 2; i <= 3; i++) {
if ((mp[r][c+1] == 1 || mp[r][c+1] == i) && (mp[r+1][c] == 1 || mp[r+1][c] == i)) {
code[c] = i;
code[c-1] = i;
hm[cur^1].push(encode(), hm[cur].f[k]+1);
}
}
}
}
}
void dpblock(int r, int c, int cur)
{
for (int k = 0; k < hm[cur].size; k++) {
decode(hm[cur].state[k]);
if (code[c-1] || code[c]) continue;
code[c] = code[c-1] = 0;
if (c == m) shift();
hm[cur^1].push(encode(), hm[cur].f[k]);
}
}
int main()
{
while (cin >> n >> m) {
if (!n) break;
memset(mp, 0, sizeof(mp));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> mp[i][j];
if (mp[i][j] < 2) mp[i][j] ^= 1;
}
}
int cur = 0;
hm[cur].init();
hm[cur].push(0, 0);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
hm[cur^1].init();
if (mp[i][j]) dpblank(i, j, cur);
else dpblock(i, j, cur);
cur ^= 1;
}
}
int ans = 0;
for (int i = 0; i < hm[cur].size; i++) {
ans += hm[cur].f[i];
}
if (ans >= 2) ans -= 2;
cout << ans << endl;
}
return 0;
}