UVA_10572

    由于具有连通性的要求,所以可以用插头dp来处理,这样需要记录下来轮廓线上格子的颜色以及连通状况,在dp的时候需要考虑全面不合法的情况,具体的思路可以参考另一个题的题解:http://www.cnblogs.com/staginner/archive/2012/09/17/2688634.html。

    在最坏的情况下即8*8全部是'.',递推到每个格子的状态总数也没超过10000。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define HASH 10007
#define MAXD 10010
int N, M, pre[65][MAXD];
char g[10][10], op[65][MAXD];
struct HashMap
{
    int head[HASH], size, next[MAXD], st[MAXD], col[MAXD], dp[MAXD];
    void init()
    {
        memset(head, -1, sizeof(head)), size = 0;    
    }
    void push(int _st, int _col, int _dp, int id, int k, char ch)
    {
        int i, h = ((_st << 6) + _col) % HASH;
        for(i = head[h]; i != -1; i = next[i])
            if(st[i] == _st && col[i] == _col)
            {
                dp[i] += _dp;
                return ;    
            }
        st[size] = _st, col[size] = _col, dp[size] = _dp;
        pre[id][size] = k, op[id][size] = ch;
        next[size] = head[h], head[h] = size ++;
    }
}hm[2];
int code[10], h[10];
int encode(int *code, int m)
{
    int i, st = 0, cnt = -1;
    memset(h, -1, sizeof(h));
    for(i = 0; i < m; i ++)
    {
        if(h[code[i]] == -1) h[code[i]] = ++ cnt;
        st = st << 3 | h[code[i]];    
    }
    return st;
}
void decode(int *code, int m, int st)
{
    for(int i = m - 1; i >= 0; i --) code[i] = st & 7, st >>= 3;    
}
void init()
{
    int i;
    scanf("%d%d", &N, &M);
    for(i = 0; i < N; i ++) scanf("%s", g[i]);    
}
void dp(int i, int j, int c, int cur)
{
    int k;
    for(k = 0; k < hm[cur].size; k ++)
    {
        int col = hm[cur].col[k], u = i ? (col >> j & 1) == c : 0, l = j ? (col >> j - 1 & 1) == c : 0, lu = (col >> M) == c;    
        if(u && l && lu) continue;
        if(i == N - 1 && j == M - 1 && !u && !l && lu) continue;
        decode(code, M, hm[cur].st[k]);
        if(i && !u)
        {
            int s1 = 0, s2 = 0;
            for(int t = 0; t < M; t ++)
            {
                if(code[t] == code[j]) ++ s1;
                if((col >> t & 1) != c) ++ s2;    
            }
            if(s1 == 1)
            {
                if(s2 > 1) continue;
                if(i < N - 1 || j < M - 2) continue;    
            }
        }
        if(u && l)
        {
            if(code[j] != code[j - 1])
                for(int t = 0, x = code[j]; t < M; t ++)
                    if(code[t] == x) code[t] = code[j - 1];    
        }
        else if(!u && l) code[j] = code[j - 1];
        else if(!u && !l) code[j] = M;
        
        if(col & 1 << j) col |= 1 << M;
        else col &= ~(1 << M);
        if(c) col |= 1 << j;
        else col &= ~(1 << j);
        
        hm[cur ^ 1].push(encode(code, M), col, hm[cur].dp[k], i * M + j, k, c ? '#' : 'o');
    }
}
void print(int k)
{
    int i, j;
    for(i = N - 1; i >= 0; i --)
        for(j = M - 1; j >= 0; j --)
            g[i][j] = op[i * M + j][k], k = pre[i * M + j][k];
    for(i = 0; i < N; i ++) puts(g[i]);
}
void solve()
{
    int i, j, k, cur = 0, ans = 0;
    hm[0].init();
    hm[0].push(0, 0, 1, 0, 0, 0);
    for(i = 0; i < N; i ++)
        for(j = 0; j < M; j ++)
        {
            hm[cur ^ 1].init();
            if(g[i][j] != '#') dp(i, j, 0, cur);
            if(g[i][j] != 'o') dp(i, j, 1, cur);
            cur ^= 1;
        }
    for(i = 0; i < hm[cur].size; i ++)
    {
        int max = 0;
        decode(code, M, hm[cur].st[i]);
        for(j = 0; j < M; j ++) max = std::max(max, code[j]);
        if(max > 1) continue;
        ans += hm[cur].dp[i], k = i;
    }
    printf("%d\n", ans);
    if(ans != 0) print(k);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t --)
    {
        init();
        solve();
        printf("\n");
    }
    return 0;    
}

 

 

posted on 2012-09-17 15:47  Staginner  阅读(680)  评论(0编辑  收藏  举报