UVa11443 Tree in a Grid

UVa11443 Tree in a Grid

  • 题目链接
  • 题意
  • 分析
  • AC 代码

题目链接

  UVa11443 Tree in a Grid

题意

  有一个 r 行c 列的点阵(1≤r≤200,1≤c≤8),行从上到下编号为0r-1,列从左到右编号为0c-1。第i 行j 列的点记为(i,j),它的上、左、下、右相邻点的坐标分别为(i-1,j)、(i,j-1)、(i+1,j)和(i,j+1)。(i,j)和这4 个点(如果存在的话)之间可以连一条边。
  目前,这个点阵中有一些边已经连好,你的任务是继续连边,使得点阵中的所有点连通,但不构成环,然后统计方案总数除以md 的余数(1≤md≤1000000)。

分析

  插头DP里面的路径模型问题。插头DP的路径问题需要利用最小表示法处理路径的生成、合并与消失的情况。本题最后要合并成一条路径且不是回路,因此dp时路径消失的情况非法并且路径合并时不得产生环

AC 代码

#include 
#include 
using namespace std;

#define T 1430
#define M 200
#define N 8

int d[2][T], f[M*N], p[1<<(3*N-5)], r[T], a[N], b[N+1], c, m, n, md, t; char s[M<<1][N<<1];

int find(int x) {
    return x == f[x] ? x : f[x] = find(f[x]);
}

void decode(int x) {
    for (int i=n-1; i>=0; --i) a[i] = x&7, x >>= 3;
}

bool valid(int x) {
    decode(x);
    for (int i=0; i<n; ++i) for (int j=i+2; j<n; ++j) if (a[i] == a[j])
        for (int k=i+1; k<j; ++k) if (a[i] != a[k]) for (int t=j+1; t<n; ++t) if (a[k] == a[t]) return false;
    return true;
}

int rep() {
    for (int i=0, j=0, k; i<n; ++i) {
        for (k=0; k<i; ++k) if (a[k] == a[i]) break;
        if (k == i) b[a[i]] = j++;
    }
    int y = 0;
    for (int i=0; i<n; ++i) y = y<<3 | b[a[i]];
    return y;
}

int rep(int x) {
    decode(x);
    return rep();
}

int cnt(int x) {
    int c = 0;
    for (int i=0; i<n; ++i) if (a[i] == x) ++c;
    return c;
}

void solve() {
    cin >> m >> n >> md; cin.get();
    for (int i=0, r=(m<<1)-1; i<r; ++i) cin.getline(s[i], n<<1);
    for (int i=0, k=0; i<m; ++i) for (int j=0; j<n; ++j, ++k) {
        f[k] = k;
        if (i && s[(i<<1)-1][j<<1] != ' ') f[k] = k-n;
        if (j && s[i<<1][(j<<1)-1] != ' ') {
            int u = find(k-1), v = find(k);
            if (u == v) {
                cout << "Impossible" << endl;
                return;
            }
            f[v] = u;
        }
    }
    for (int i=c=0, x=1<<(3*n-5); i<x; ++i) if (valid(i) && rep(i) == i) r[p[i] = c++] = i;
    memset(d[0], 0, sizeof(d[0])); d[0][c-1] = 1;
    for (int i=0, e=1; i<m; ++i) for (int j=0; j<n; ++j, e^=1) {
        memset(d[e], 0, sizeof(d[e]));
        for (int k=0; k<c; ++k) if (d[e^1][k]) {
            decode(r[k]);
            const int t = a[j], l = j ? a[j-1] : -1, dd = d[e^1][k];
            if (!j || s[i<<1][(j<<1)-1] == ' ') d[e][k] = (d[e][k] + dd) % md;
            if (cnt(t) != 1) {
                if (j && (!i || s[(i<<1)-1][j<<1] == ' ')) {
                    a[j] = l;
                    int &f = d[e][p[rep()]]; f = (f + dd) % md;
                }
                if ((!i || s[(i<<1)-1][j<<1] == ' ') && (!j || s[i<<1][(j<<1)-1] == ' ')) {
                    decode(r[k]); a[j] = n;
                    int &f = d[e][p[rep()]]; f = (f + dd) % md;
                }
            }
            if (l >= 0 && l != t) {
                decode(r[k]);
                for (int b=0; b<n; ++b) if (a[b] == t) a[b] = l;
                int &f = d[e][p[rep()]]; f = (f + dd) % md;
            }
        }
    }
    cout << d[m*n&1][0] << endl;
}

int main() {
    cin >> t;
    while (t--) solve();
    return 0;
}

你可能感兴趣的:(UVa11443 Tree in a Grid)