URAL - 1519 Formula 1 (插头DP)

这里写链接内容

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

如果看不懂可以问

//下面所说的情况全在论文中的第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[N][N];
int pow3[N];

//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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 02:36:45

URAL - 1519 Formula 1 (插头DP)的相关文章

【bzoj1814】Ural 1519 Formula 1 插头dp

题目描述 一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数. 输入 The first line contains the integer numbers N and M (2 ≤ N, M ≤ 12). Each of the next N lines contains M characters, which are the corresponding cells of the rectangle. Character "." (full stop)

bzoj 1814: Ural 1519 Formula 1 插头dp经典题

用的括号序列,听说比较快. 然并不会预处理,只会每回暴力找匹配的括号. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 199917 6 #define ll long long 7 #define bp 1<<bit[j-1] 8 #define bq 1<<bit[j] 9 using nam

【URAL 1519】【插头dp模板】Formula 1

1519. Formula 1 Time limit: 1.0 second Memory limit: 64 MB Background Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely

[URAL 1519] Formula 1 轮廓线DP 括号序列

题意 n * m 的矩形, 有坏点, 问哈密顿回路数量. n, m <= 11 . 分析 1. 确立状态 我们考虑轮廓线DP. 为此, 我们要刻画并量化轮廓线的相关信息: ① 插头是否存在? ② 插头的连通性. 我们发现: 插头一一对应, 且互不相交. 于是考虑使用括号序列刻画轮廓线. 至于量化, 我们将一个括号序列当做一个三进制数即可. 2. 转移 从上一行的最后一个, 转移到当前行的第一个: 位移. 当前格子为坏点: 对于没有插头插到当前点的状态原样复制. 否则: (1) L = # , R

bzoj1814: Ural 1519 Formula 1 2011-12-20

1814: Ural 1519 Formula 1Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 263  Solved: 70[Submit][Status][Discuss]DescriptionRegardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well- known, that the 

URAL 1519 Formula 1 (插头DP,常规)

题意:给一个n*m的矩阵,格子中是'*'则是障碍格子,不允许进入,其他格子都是必走的格子,所走格子形成一条哈密顿回路,问有多少种走法? 思路: 本来是很基础的题,顿时不知道进入了哪个坑.这篇插头DP的文章够详细,推荐一看(最好不要照抄代码). 细节要小心,比如输出用I64d,必须用long long,判断是否无哈密顿回路,位操作等等. 这次仍然用括号表示法,1表示(,2表示). 1 #include <bits/stdc++.h> 2 #define pii pair<int,int&g

Ural1519 Formula 1(插头dp)

原题网址:http://acm.timus.ru/problem.aspx?space=1&num=1519 有关插头dp和状态压缩请参考:http://wenku.baidu.com/link?url=AFuYe_EfR5yXMNK0rY-TaLe6LLgKhsOVxBM1RQULxElPrvjQVlO724nUxlXtaDx4aLp7FHIz8AexYiTy06_r4CV5XUs6c9lM5vpz5kDr6HG 详细代码(c++): 1 #include <cstdio> 2 #i

[URAL1519] Formula 1 [插头dp入门]

题面: 传送门 思路: 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是回路,所以联通块上方的插头一定两两配对,可以使用括号序列代替最小表示法 分情况讨论一下 情况一:当前格子上方和左方都没有插头 这种时候可以继续,也可以给当前格子加一个下插头一个右插头,相当于一个新的联通分量 情况二:上方有一个下插头,左边没有 这时有两个决策:可以向右转,也可以继续向下,操作就是分别给这个格子一个右插

【插头DP】URAL 1519 Formula 1

通道:http://acm.timus.ru/problem.aspx?space=1&num=1519 题意:单回路,经过全部可达点,有阻碍点. 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 13; const int MAX_M = 13; const int HASH = 10007; const in