URAL 1519 Formula 1

URAL_1519

    插头dp的处女作终于完成啦^_^

    具体的思路还是参考陈丹琦的论文吧,我也只是处于学习和模仿的阶段。我是仿照胡浩博客用最小表示法敲的代码,更多和插头dp相关的内容可以参考胡浩的博客:http://www.notonlysuccess.com/index.php/plug-dp-complete/

#include<stdio.h>

#include<string.h>

#define MAXD 15

#define HASH 30007

#define SIZE 1000010

int N, M, maze[MAXD][MAXD], code[MAXD], ch[MAXD], ex, ey;

char b[MAXD];

struct Hashmap

{

    int size, head[HASH], next[SIZE];

    long long f[SIZE], state[SIZE];

    void init()

    {

        memset(head, -1, sizeof(head));

        size = 0;

    }

    void push(long long st, long long ans)

    {

        int i, h = st % HASH;

        for(i = head[h]; i != -1; i = next[i])

            if(state[i] == st)

            {

                f[i] += ans;

                return ;

            }

        state[size] = st, f[size] = ans;

        next[size] = head[h];

        head[h] = size ++;

    }

}hm[2];

void decode(int *code, int m, long long st)

{

    int i;

    for(i = m; i >= 0; i --)

    {

        code[i] = st & 7;

        st >>= 3;

    }

}

long long encode(int *code, int m)

{

    int i, cnt = 1;

    long long st = 0;

    memset(ch, -1, sizeof(ch));

    ch[0] = 0;

    for(i = 0; i <= m; i ++)

    {

        if(ch[code[i]] == -1)

            ch[code[i]] = cnt ++;

        code[i] = ch[code[i]];

        st <<= 3;

        st |= code[i];

    }

    return st;

}

void init()

{

    int i, j, k;

    memset(maze, 0, sizeof(maze));

    ex = 0;

    for(i = 1; i <= N; i ++)

    {

        scanf("%s", b + 1);

        for(j = 1; j <= M; j ++)

            if(b[j] == '.')

                maze[ex = i][ey = j] = 1;

    }

}

void shift(int *code, int m)

{

    int i;

    for(i = m; i > 0; i --)

        code[i] = code[i - 1];

    code[0] = 0;

}

void dpblank(int i, int j, int cur)

{

    int k, t, left, up;

    for(k = 0; k < hm[cur].size; k ++)

    {

        decode(code, M, hm[cur].state[k]);

        left = code[j - 1], up = code[j];

        if(left && up) // case 1

        {

            if(left == up)

            {

                if(i == ex && j == ey)

                {

                    code[j - 1] = code[j] = 0;

                    if(j == M)

                        shift(code, M);

                    hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

                }

            }

            else

            {

                code[j - 1] = code[j] = 0;

                for(t = 0; t <= M; t ++)

                    if(code[t] == up)

                        code[t] = left;

                if(j == M)

                    shift(code, M);

                hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

            }

        }

        else if(left) // case 2

        {

            if(maze[i][j + 1])

            {

                code[j - 1] = 0, code[j] = left;

                hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

            }

            if(maze[i + 1][j])

            {

                code[j - 1] = left, code[j] = 0;

                if(j == M)

                    shift(code, M);

                hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

            }

        }

        else if(up) // case 3

        {

            if(maze[i][j + 1])

            {

                code[j - 1] = 0, code[j] = up;

                hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

            }

            if(maze[i + 1][j])

            {

                code[j - 1] = up, code[j] = 0;

                if(j == M)

                    shift(code, M);

                hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

            }

        }

        else // case 4

        {

            if(maze[i][j + 1] && maze[i + 1][j])

            {

                code[j - 1] = code[j] = 13;

                hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

            }

        }

    }

}

void dpblock(int i, int j, int cur)

{

    int k;

    for(k = 0; k < hm[cur].size; k ++)

    {

        decode(code, M, hm[cur].state[k]);

        code[j - 1] = code[j] = 0;

        if(j == M)

            shift(code, M);

        hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]);

    }

}

void solve()

{

    int i, j, cur = 0;

    long long ans = 0;

    hm[cur].init();

    hm[cur].push(0, 1);

    for(i = 1; i <= N; i ++)

        for(j = 1; j <= M; j ++)

        {

            hm[cur ^ 1].init();

            if(maze[i][j])

                dpblank(i, j, cur);

            else

                dpblock(i, j, cur);

            cur ^= 1;

        }

    for(i = 0; i < hm[cur].size; i ++)

        ans += hm[cur].f[i];

    printf("%lld\n", ans);

}

int main()

{

    while(scanf("%d%d", &N, &M) == 2)

    {

        init();

        if(ex == 0)

            printf("0\n");

        else

            solve();

    }

    return 0;

}

你可能感兴趣的:(form)