fzu_1977 Pandora adventure

题目:

  The pollution of the earth is so serious that people can not survive any more. Fortunately, people have found a new planet that maybe has life, and we call it "Pandora Planet".
  Leonardo Da Vinci is the only astronaut on the earth. He will be sent to the Pandora Planet to gather some plant specimens and go back. The plant specimen is important to the people to decide whether the planet is fit to live or not.
  Assuming that Da Vinci can only move in an N×M grid. The positions of the plant specimens he wants to collect are all marked by the satellite. His task is to find a path to collect all the plant specimens and return to the spaceship. There are some savage beasts in the planet. Da Vinci can not investigate the grid with the savage beast. These grids are also marked by the satellite. In order to save time Da Vinci could only visit each grid exactly once and also return to the start grid, that is, you can not visit a grid twice except the start grid. You should note that you can choose any grid as the start grid.
  Now he wants to know the number of different paths he can collect all the plant specimens. We only care about the path and ignore where the start grid is, so the two paths in Figure 1 are considered as the same.

思路:

  • 关于插头dp:

  按照惯例,每次学新算法都会有一篇学习笔记的(而且往往这个笔记还十分没意义)
  插头dp应该算是轮廓线dp的一种扩展吧。对于一类求路径或回路(连通性)的问题,在转移状态中不要求路径已经连通,而是在轮廓线上记录路径形成的插头,最后只要所有的插头都合法的连在一起就说明形成了一个合法的路径(回路)。
  最后再放上带自己入门的博客

  • 关于本题:
      题目要求用恰好一个回路走遍整个图,而如果只用 在轮廓线上维护插头就会导致形成多条回路。因为每一段部分回路在当前的轮廓线上一定存在左右两个点,所以用 分别标记左右两点。当左边是 右边是 时这个两个点肯定是属于一个线段的,为了保证只有一个回路,只能在最后一个可达点才能进行这种转移。中间转移的部分情况较多,可以画图思考(或参考那篇博客)。
      因为有三种状态,所以实现的时候一般用 进制保存,用哈希表维护dp数组。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define File(_) freopen(#_ ".in", "r", stdin), freopen(#_ ".out", "w", stdout)
#define ALL(x) x.begin(), x.end()
#define mset(a, b) memset(a, b, sizeof a)
#define rep(i, a, b) for(int i(a), i##_END_(b); i <= i##_END_; i++) 
#define drep(i, a, b) for(int i(a), i##_END_(b); i >= i##_END_; i--)
template<class T> inline bool tomax(T &a, T b) {return a < b ? a = b, 1 : 0;}
template<class T> inline bool tomin(T &a, T b) {return b < a ? a = b, 1 : 0;}
typedef long long ll;
typedef double db;

const int MOD = 1e6 + 3;
struct Hash_Table {
    int rel[MOD], vec[MOD], siz;
    ll key[MOD];
    void clear() {
        rep(i, 1, siz) rel[vec[i]] = -1;
        siz = 0;
    }
    ll& operator[] (int val) {
        int pos = val % MOD;
        while(rel[pos] != -1) {
            if(rel[pos] == val) break;
            pos = (pos + 1) % MOD;
        }
        if(rel[pos] == -1) {rel[pos] = val; key[pos] = 0; vec[++siz] = pos;}
        return key[pos];
    }
} dp[2];

inline int get(int bin, int x) {
    return bin >> (x * 2) & 3;
}
int set(int bin, int x, int k) {
    int t = get(bin, x);
    bin ^= t << (x * 2);
    bin |= k << (x * 2);
    return bin;
}
inline int set(int bin, int x1, int k1, int x2, int k2) {
    return set(set(bin, x1, k1), x2, k2);
}
int find(int bin, int x, int d) {
    int c = 0, t = get(bin, x);
    if(t == 1) c++;
    if(t == 2) c--;
    while(c) {
        x += d;
        t = get(bin, x);
        if(t == 1) c++;
        if(t == 2) c--;
    }
    return x;
}

char getAChar() {
    char c;
    do c = getchar(); while(c == ' ' || c == '\n' || c == '\r');
    return c;
}

char mp[20][20];
int main() {
    // freopen("data.in", "r", stdin);
    int cas, n, m;
    scanf("%d", &cas);
    mset(dp[0].rel, -1); mset(dp[1].rel, -1);
    rep(test_id, 1, cas) {
        scanf("%d%d", &n, &m);
        rep(i, 1, n) rep(j, 1, m) mp[i][j] = getAChar();
        int o = 1, d = 0;
        dp[o].clear(); dp[o][0] = 1;
        rep(i, 1, n) {
            rep(j, 1, m) {
                std::swap(o, d);
                dp[o].clear();
                rep(x, 1, dp[d].siz) {
                    int _x = dp[d].vec[x];
                    int bin = dp[d].rel[_x];
                    ll val = dp[d].key[_x];
                    int b1 = get(bin, j), b2 = get(bin, j + 1), cir = get(bin, 0);
                    if(mp[i][j] == 'X' || mp[i][j] == '*') {
                        if(b1 == 0 && b2 == 0)
                            dp[o][bin] += val;
                    }
                    if(mp[i][j] == 'O' || mp[i][j] == '*') {
                        if(b1 == 0 && b2 == 0) 
                            dp[o][set(bin, j, 1, j + 1, 2)] += val;
                        else if(b1 != 0 && b2 == 0) {
                            dp[o][bin] += val;
                            dp[o][set(bin, j, 0, j + 1, b1)] += val;
                        }
                        else if(b1 == 0 && b2 != 0) {
                            dp[o][bin] += val;
                            dp[o][set(bin, j, b2, j + 1, 0)] += val;
                        }
                        else if(b1 == 2 && b2 == 1) 
                            dp[o][set(bin, j, 0, j + 1, 0)] += val;
                        else if(b1 == 1 && b2 == 1) {
                            int pos = find(bin, j + 1, 1);
                            int tmp = set(bin, j, 0, j + 1, 0);
                            dp[o][set(tmp, pos, 1)] += val;
                        }
                        else if(b1 == 2 && b2 == 2) {
                            int pos = find(bin, j, -1);
                            int tmp = set(bin, j, 0, j + 1, 0);
                            dp[o][set(tmp, pos, 2)] += val;
                        }
                        else if(b1 == 1 && b2 == 2 && cir == 0) {
                            int tmp = set(bin, j, 0, j + 1, 0);
                            dp[o][set(tmp, 0, 1)] += val;
                        }
                    }
                }
            }
            if(i != n) {
                std::swap(o, d);
                dp[o].clear();
                rep(x, 1, dp[d].siz) {
                    int _x = dp[d].vec[x];
                    int bin = dp[d].rel[_x];
                    ll val = dp[d].key[_x];
                    if(bin < (1 << (2 * m + 2))) {
                        int t = get(bin, 0);
                        dp[o][set(set(bin, 0, 0) << 2, 0, t)] += val;
                    }
                }
            }
        }
        printf("Case %d: %I64d\n", test_id, dp[o][1]);
    }
    return 0;
}