您的位置:首页 > 其它

URAL - 1519 Formula 1 (插头DP)

2015-07-20 17:33 309 查看
这里写链接内容

刚开始学插头dp好吃力,看了别人的代码有点看不懂,所以就参考了别人的代码,写了注释,希望有帮助

如果看不懂可以问

[code]//下面所说的情况全在论文中的第13页
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 13
#define S1 14000
#define S2 1600000
struct Queue{
    int opt;
    long long sum;
}Q[2][S1];

char g

;
int pow3
;

//cnt指的是状态有多少种
int cnt[2];

//state[][j]指的是j这种状态的序号是多少
int state[2][S2];

int n, m, final, now;

//得到第col列的状态
int get(int opt, int col) {
    return opt / pow3[col] % 3;
}

//将第col列设置成value
int set(int opt, int col, int value) {
    return opt + (value - get(opt, col)) * pow3[col];
}

//这是记忆化宽度优先搜索的的解法,插入队列
void enqueue(int opt, int col, long long sum) {

    //如果是最后一列,且最后一列还有右插头,这就不符合了,第m个存储的是第col列的右插头
    if (col == m - 1 && get(opt, m))
        return ;

    //找出opt这个状态的序号
    int &id = state[now][opt];

    //如果拓展过
    if (id) 
        Q[now][id].sum += sum;
    else {
        //没拓展过
        id = ++cnt[now];
        Q[now][id].opt = opt;
        Q[now][id].sum = sum;
    }
}

//改变状态,这种情况是论文中的情况2.1
int change1(int opt, int i) {
    for (int flag = 0; i < m; i++) {
        int tmp = get(opt, i);
        if (tmp == 1)
            flag++;
        else if (tmp == 2)
            flag--;
        if (!flag)
            return set(opt, i, 1);
    }
    return -1;
}

//改变状态,这种情况是论文中的情况2.2
int change2(int opt, int i) {
    for (int flag = 0; i >= 0; i--) {
        int tmp = get(opt, i);
        if (tmp == 2)
            flag++;
        else if (tmp == 1)
            flag--;
        if (!flag)
            return set(opt, i, 2);
    }
    return -1;
}

void init() {

    pow3[0] = 1;
    for (int i = 1; i < N; i++)
        pow3[i] = pow3[i - 1] * 3;

    scanf("%d%d", &n, &m);
    now = 0;
    for (int i = 0; i < n; i++) {
        scanf("%s", g[i]);
        for (int j = 0; j < m; j++)
            if (g[i][j] == '.')
                final = i * m + j;
    }
    enqueue(0,0,1);
}

void solve() {
    now ^= 1;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            for (int k = 1, l = cnt[now ^ 1]; k <= l; k++) {
                int opt = Q[now ^ 1][k].opt;
                long long sum = Q[now ^ 1][k].sum;
                int left = get(opt, m), up = get(opt, j);

                if (g[i][j] == '*') {
                    if (left == 0 && up == 0)
                        enqueue(opt, j, sum);
                    continue;
                } 
                //论文中的情况1
                if (left == 0 && up == 0) {
                    enqueue(set(set(opt, m, 2), j, 1), j, sum);
                }//论文中的情况2.1
                else if (left == 1 && up == 1) {
                    int tmp = change1(opt, j);
                    enqueue(set(set(tmp, m, 0), j, 0), j, sum);
                }//论文中的情况2.2
                else if (left == 2 && up == 2) {
                    int tmp = change2(opt, j);
                    enqueue(set(set(tmp, m, 0), j, 0), j, sum);
                }//论文中的情况2.3
                else if (left == 1 && up == 2) {
                    if (i * m + j == final) 
                        enqueue(set(set(opt, m, 0), j, 0), j, sum);
                }//论文中的情况2.4
                else if (left == 2 && up == 1) {
                    enqueue(set(set(opt, m, 0), j, 0), j, sum);
                } //论文中的情况3
                else if (left == 0 || up == 0) {
                    enqueue(set(set(opt, m, 0), j, left + up), j, sum);
                    enqueue(set(set(opt, j, 0), m, left + up), j, sum);
                }
            }
            now ^= 1;
            for(int k = 1, t = cnt[now]; k <= t; k++)
                state[now][Q[now][k].opt] = 0;
            cnt[now] = 0;
        }

    printf("%lld\n", Q[now ^ 1][state[now ^ 1][0]].sum);
}

int main() {
    init();
    solve();
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: