确定起点和终点的俩条简单路径问题,可以规定每个格子只能有2号插头或3号插头或空插头,允许合并相同编号的插头,这样可能会产生冗余的回路,但由于此题求得是最小解,所以这种情况会被筛选掉,当然如果求最长路径的话就不能这样了,只能使用最小表示法编号,然后合并不同编号的插头。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(200010); const int MAXM(5010); const int MAXE(10010); const int HSIZE(13131); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const int MOD(123456791); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); int N, M; int mp[10][10]; void checkmin(int &op1, int op2) {if(op2 < op1) op1 = op2;} struct HASH_MAP { int first[HSIZE]; int next[MAXN], state[MAXN]; int value[MAXN]; int size; void init() { memset(first, -1, sizeof(first)); size = 0; } void insert(int ts, int tv) { int h = ts%HSIZE; for(int i = first[h]; ~i; i = next[i]) if(state[i] == ts) { checkmin(value[i], tv); return; } value[size] = tv; state[size] = ts; next[size] = first[h]; first[h] = size++; } } hm[2]; HASH_MAP *cur, *last; int code[10]; void decode(int ts) { for(int i = 0; i <= M; ++i) { code[i] = ts&3; ts >>= 2; } } int encode() { int ret = 0; for(int i = M; i >= 0; --i) ret = (ret << 2)|code[i]; return ret; } void updata(int x, int y, int tv) { int left = (y == 0)? 0: code[y]; int up = (x == 0)? 0: code[y+1]; if(mp[x][y] == 1) { if(left == 0 && up == 0) { code[y] = code[y+1] = 0; cur->insert(encode(), tv); } return ; } if(mp[x][y] == 2 || mp[x][y] == 3) { if(left == 0 && up == 0) { if(x < N-1) { code[y] = mp[x][y]; code[y+1] = 0; cur->insert(encode(), tv+1); } if(y < M-1) { code[y] = 0; code[y+1] = mp[x][y]; cur->insert(encode(), tv+1); } } else if(left == 0 || up == 0) { if(left+up == mp[x][y]) { code[y] = code[y+1] = 0; cur->insert(encode(), tv+1); } } return; } if(left == 0 && up == 0) { code[y] = code[y+1] = 0; cur->insert(encode(), tv); if(x == N-1 || y == M-1) return; code[y] = code[y+1] = 2; cur->insert(encode(), tv+2); code[y] = code[y+1] = 3; cur->insert(encode(), tv+2); } else if(left == 0 || up == 0) { if(x < N-1) { code[y] = up+left; code[y+1] = 0; cur->insert(encode(), tv+2); } if(y < M-1) { code[y] = 0; code[y+1] = up+left; cur->insert(encode(), tv+2); } } else if(left == up) { code[y] = code[y+1] = 0; cur->insert(encode(), tv+2); } } void solve() { cur = hm; last = hm+1; last->init(); last->insert(0, 0); for(int i = 0; i < N; ++i) { int sz = last->size; for(int k = 0; k < sz; ++k) last->state[k] <<= 2; for(int j = 0; j < M; ++j) { cur->init(); sz = last->size; for(int k = 0; k < sz; ++k) { decode(last->state[k]); updata(i, j, last->value[k]); } swap(cur, last); } } int ans = 0; for(int i = 0; i < last->size; ++i) if(last->state[i] == 0) { ans = last->value[i]; break; } printf("%d\n", ans/2); } int main() { while(scanf("%d%d", &N, &M), N+M) { for(int i = 0; i < N; ++i) for(int j = 0; j < M; ++j) scanf("%d", mp[i]+j); solve(); } return 0; }