【Learning】适妞来学 插头 dp

来源:互联网 发布:原始dbc数据 编辑:程序博客网 时间:2024/04/27 22:34

极其仰慕 邝斌 巨巨!!!!!! Orz

资料

http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html

Problem List

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=23691#overview


Step By Step

A - Eat the Trees

最简单的,表示一下就行了。。

注意转移。

第一次照木板敲,以后就学会了把。。。

const int N = 20;int n , m;int code[N] , a[N][N];    const int HashSize = 1e4 + 9;    const int StateSize = 1e6 + 9;struct HashMap{    int head[HashSize] , next[StateSize] , state[StateSize] , size;    LL f[StateSize];    void init(){        size = 0;        FLC(head , -1);    }    void push(int st , LL inc){        int h = st % HashSize;        for (int i = head[h] ; ~i ; i = next[i])            if (st == state[i]){                f[i] += inc;                return;            }        f[size] = inc;        state[size] = st;        next[size] = head[h];        head[h] = size++;    }}H[2];int encode(int * code , int m){    int st = 0;    for (int i = 0 ; i <= m ; ++i)        st = st << 1 | code[i];    return st;}void decode(int * code , int m , int st){    for (int i = m ; i >= 0 ; --i){        code[i] = st & 1;        st >>= 1;    }}void shift(int *code , int m){      // Another Line    for (int i = m ; i > 0 ; --i)        code[i] = code[i - 1];    code[0] = 0;}void dpblank(int x , int y , int cur){    int left , up;    for (int i = 0 ; i < H[cur].size ; ++i){        decode(code , m , H[cur].state[i]);        left = code[y - 1];        up = code[y];        if (left && up){    // 11 -> 00            code[y - 1] = code[y] = 0;            if (y == m) shift(code , m);            H[cur ^ 1].push( encode(code , m) , H[cur].f[i] );        }        else if (left || up){   // 10 | 01            if (a[x][y + 1]){   // Go right                code[y - 1] = 0;                code[y] = 1;                if (y == m) shift(code , m);                H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);            }            if (a[x + 1][y]){   // Go down                code[y - 1] = 1;                code[y] = 0;                if (y == m) shift(code , m);                H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);            }        }        else{   // 00            if (a[x][y + 1] && a[x + 1][y]){    // down to right                code[y] = code[y - 1] = 1;                H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);            }        }    }}void dpblock(int x , int y , int cur){    for (int i = 0 ; i < H[cur].size ; ++i){        decode(code , m , H[cur].state[i]);        code[y - 1] = code[y] = 0;        if (y == m) shift(code , m);        H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);    }}int Case;void solve(){    scanf("%d%d" , &n , &m);    for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j)        scanf("%d" , &a[i][j]);    for (int i = 1 ; i <= n ; ++i) a[i][0] = a[i][m + 1] = 0;    for (int i = 1 ; i <= m ; ++i) a[0][i] = a[n + 1][i] = 0;    LL ans = 0;    int cur = 0;    H[cur].init();    H[cur].push(0 , 1);    for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){        H[cur ^ 1].init();        if (a[i][j]) dpblank(i , j , cur);        else dpblock(i , j , cur);        cur ^= 1;    }    for (int i = 0 ; i < H[cur].size ; i++)        ans += H[cur].f[i];    printf("Case %d: There are %I64d ways to eat the trees.\n",++Case , ans);}int main(){    int _;Case = 0;    cin >> _;    while(_--) solve();}


B - Formula 1

三进制 -> 四进制的括号表示

括号表示还是相当快的!

http://blog.sina.com.cn/s/blog_51cea4040100gmky.html

这个blog 写的很清楚 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑

struct Hashmap{    const static int HASHSIZE = 1e5 + 7;    const static int STATUSSIZE = 1e5 + 9;    int head[HASHSIZE];    struct hash_item{        int key;        LL val;        int next;    }item[STATUSSIZE + 1];    int L;    int getHash(int x){        return x % HASHSIZE;    }    void init(){        memset(head , -1 , sizeof(head));        L = 0;    }    void clear(){        for (int i = 0; i < L ; ++i)            head[getHash(item[i].key)] = -1;        L = 0;    }    int contains(int x){        for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)            if (item[i].key == x)                return i;        return -1;    }    void insert(int x){        int tmp = getHash(x);        item[L].key = x;        item[L].val = 0;        item[L].next = head[tmp];        head[tmp] = L++;    }    LL& operator[] (int x){        int tmp = contains(x);        if (tmp == -1){            insert(x);            return item[L - 1].val;        }        else return item[tmp].val;    }}hm[2];const int N = 15;int n , m;int code[N] , a[N][N];int ex , ey;char str[N];void shift(int &code){    code <<= 2;    int mm = (m + 1) << 1;    code &= ((1 << mm) - 1);}int getplug(int cur , int y){    cur >>= 2 * y;    int ret = cur & 1;    cur >>= 1;    ret |= (cur & 1) << 1;    return ret;}void setplug(int &cur , int y , int key){    if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);    if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);}void dpblank(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left == 0 && up == 0){  //无插头,新建联通分量            if (a[x + 1][y] && a[x][y + 1]){                setplug(aft , y - 1 , 1);                setplug(aft , y , 2);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }        }        else if (left && up){   // 有两个插头 ! 要删掉上插头和左插头啊            if (left == 1 && up == 1){  // ((  找到下一个对应的 ) 改成 (                int top = 0;                for (int j = y ; j <= m ; ++j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 1) ++top;                    if (plug == 2) --top;                    if (top == 0){                        setplug(aft , j , 1);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }            else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )                int top = 0;                for (int j = y - 1 ; j >= 0 ; --j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 2) ++top;                    if (plug == 1) --top;                    if (top == 0){                        setplug(aft , j , 2);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }            else if (left == 1 && up == 2){ // () 只能在最后一个格子合并                if (x == ex && y == ey){                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }            }            else if (left == 2 && up == 1){ //  )( 维持原来状态                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }        }        else {  // 有一个插头            if (left == 0 && up){                aft = hm[cur].item[i].key;                if (a[x][y + 1]){                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }                aft = hm[cur].item[i].key;                if (a[x + 1][y]){                    setplug(aft , y - 1 , up);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }            }            else if (left && up == 0){                aft = hm[cur].item[i].key;                if (a[x + 1][y]){                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }                aft = hm[cur].item[i].key;                if (a[x][y + 1]){                    setplug(aft , y - 1 , 0);                    setplug(aft , y , left);                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }            }        }    }}void dpblock(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left || up) continue;        if (y == m) shift(aft);        hm[cur ^ 1][aft] += hm[cur].item[i].val;    }}void output(int code){    for (int i = 0 ; i <= m ; ++i){        int ret = code % 4;        code /= 4;        if (ret == 1) putchar('(');        else if (ret == 2) putchar(')');        else putchar('#');    }}void solve(){    RST(a);    for (int i = 1 ; i <= n; ++i){        scanf("%s" , str);        for(int j = 1 ; j <= m ; ++j){            a[i][j] = (str[j - 1] == '.');            if (a[i][j]){                ex = i , ey = j;            }        }    }    LL ans = 0;    int cur = 0;    hm[0].init();hm[1].init();    hm[0][0] = 1;    for (int i = 1 ; i <= n ; ++i)    for (int j = 1 ; j <= m ; ++j){        hm[cur ^ 1].clear();        if (a[i][j]) dpblank(i , j , cur);        else dpblock(i , j , cur);        cur ^= 1;    }    for (int i = 0 ; i < hm[cur].L ; ++i){        ans += hm[cur].item[i].val;    }    printf("%I64d\n" , ans);}int main(){    Case = 0;    while(~scanf("%d%d" , &n , &m)) solve();}

C - Pandora adventure

跟上一题几乎一样。还是四进制括号表示法

但是有必须走和不是必须走的格子,改变两下——

1. 不必须走的 没有 left 和 up 插头可以继续扩展,忽略格子

2. 加入 是否形成圈  这个变量。

struct Hashmap{    const static int HASHSIZE = 1e3 + 7;    const static int STATUSSIZE = 1e5 + 9;    int head[HASHSIZE];    struct hash_item{        int key;        LL val;        int next;    }item[STATUSSIZE + 1];    int L;    int getHash(int x){        return x % HASHSIZE;    }    void init(){        memset(head , -1 , sizeof(head));        L = 0;    }    void clear(){        for (int i = 0; i < L ; ++i)            head[getHash(item[i].key)] = -1;        L = 0;    }    int contains(int x){        for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)            if (item[i].key == x)                return i;        return -1;    }    void insert(int x){        int tmp = getHash(x);        item[L].key = x;        item[L].val = 0;        item[L].next = head[tmp];        head[tmp] = L++;    }    LL& operator[] (int x){        int tmp = contains(x);        if (tmp == -1){            insert(x);            return item[L - 1].val;        }        else return item[tmp].val;    }}hm[2];const int N = 15;int n , m;int a[N][N];int ex , ey;char str[N];int getplug(int cur , int y){    cur >>= 2 * y;    int ret = cur & 1;    cur >>= 1;    ret |= (cur & 1) << 1;    return ret;}int getcirlce(int cur){ //  加入连通记录,获取记录    int mm = (m + 1) << 1;    return (cur & (1 << mm)) != 0;}void setcircle(int &cur , int iscircle){ //  加入连通记录,改变    int mm = (m + 1) << 1;    if (((cur >> mm) & 1) != iscircle) cur ^= 1 << mm;}void shift(int &code){    int iscircle = getcirlce(code);    code <<= 2;    int mm = (m + 1) << 1;    code &= ((1 << mm) - 1);    setcircle(code , iscircle);}void setplug(int &cur , int y , int key){    if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);    if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);}void dpblank(int x , int y , int cur){    int left , up;    int aft;    int circle;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        circle = getcirlce(hm[cur].item[i].key);        if (left == 0 && up == 0){  //无插头,新建联通分量            if (a[x + 1][y] && a[x][y + 1]){                setplug(aft , y - 1 , 1);                setplug(aft , y , 2);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }            aft = hm[cur].item[i].key;            if (a[x][y] == 2){      // 如果不是必须走的话就可以不扩展这个格子                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }        }        else if (left && up){   // 有两个插头 ! 要删掉上插头和左插头啊            if (left == 1 && up == 1){  // ((  找到下一个对应的 ) 改成 (                int top = 0;                for (int j = y ; j <= m ; ++j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 1) ++top;                    if (plug == 2) --top;                    if (top == 0){                        setplug(aft , j , 1);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }            else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )                int top = 0;                for (int j = y - 1 ; j >= 0 ; --j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 2) ++top;                    if (plug == 1) --top;                    if (top == 0){                        setplug(aft , j , 2);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }            else if (left == 1 && up == 2){ // () 只能在最后一个格子合并                if (!circle){       //  如果没有连通的话加入连通                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 0);                    setcircle(aft , 1);                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }            }            else if (left == 2 && up == 1){ //  )( 维持原来状态                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                hm[cur ^ 1][aft] += hm[cur].item[i].val;            }        }        else {  // 有一个插头            if (left == 0 && up){                aft = hm[cur].item[i].key;                if (a[x][y + 1]){                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }                aft = hm[cur].item[i].key;                if (a[x + 1][y]){                    setplug(aft , y - 1 , up);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }            }            else if (left && up == 0){                aft = hm[cur].item[i].key;                if (a[x + 1][y]){                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }                aft = hm[cur].item[i].key;                if (a[x][y + 1]){                    setplug(aft , y - 1 , 0);                    setplug(aft , y , left);                    if (y == m) shift(aft);                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                }            }        }    }}void dpblock(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left || up) continue;        if (y == m) shift(aft);        hm[cur ^ 1][aft] += hm[cur].item[i].val;    }}void output(int code){    for (int i = 0 ; i <= m ; ++i){        int ret = code % 4;        code /= 4;        if (ret == 1) putchar('(');        else if (ret == 2) putchar(')');        else putchar('#');    }}void solve(){    RD(n , m);    RST(a);    for (int i = 1 ; i <= n; ++i){        scanf("%s" , str);        for(int j = 1 ; j <= m ; ++j){            if (str[j - 1] == '*') a[i][j] = 2;            if (str[j - 1] == 'O') a[i][j] = 1;        }    }    LL ans = 0;    int cur = 0;    hm[0].init();hm[1].init();    hm[0][0] = 1;    for (int i = 1 ; i <= n ; ++i)    for (int j = 1 ; j <= m ; ++j){        hm[cur ^ 1].clear();        if (a[i][j]) dpblank(i , j , cur);        else dpblock(i , j , cur);        cur ^= 1;    }    for (int i = 0 ; i < hm[cur].L ; ++i) {        if (getcirlce(hm[cur].item[i].key)) ans += hm[cur].item[i].val;    }    printf("Case %d: %I64d\n" , ++Case , ans);}int main(){    Case = 0;    Rush solve();}


D - Pipes

求单路径的最小分数。喜闻乐见直接套模板啊。

稍微改动的是求分数,val直接改成分数就好了。存在即有分,hashmap里面的状态都是可达的状态。

看下 喜闻乐见 的debug 方式

struct Hashmap{    const static int HASHSIZE = 1e4 + 7;    const static int STATUSSIZE = 1e5 + 9;    int head[HASHSIZE];    struct hash_item{        int key;        int val;        // val 值改成最小分数 —— “存在”即有分,不用判断是否状态可达。在 hashmap 里面的状态都可达        int next;    }item[STATUSSIZE + 1];    int L;    int getHash(int x){        return x % HASHSIZE;    }    void init(){        memset(head , -1 , sizeof(head));        L = 0;    }    void clear(){        for (int i = 0; i < L ; ++i)            head[getHash(item[i].key)] = -1;        L = 0;    }    int contains(int x){        for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)            if (item[i].key == x)                return i;        return -1;    }    void insert(int x){        int tmp = getHash(x);        item[L].key = x;        item[L].val = 0;        item[L].next = head[tmp];        head[tmp] = L++;    }    void set(int x , int y){        int tmp = contains(x);        if (tmp == -1){            insert(x);            item[L - 1].val = y;        }        checkMin(item[tmp].val , y);    }}hm[2];const int N = 15;int n , m;int a[N][N];int ex , ey;char str[N<<1][N<<1];PII score[N][N];int getplug(int cur , int y){    cur >>= 2 * y;    int ret = cur & 1;    cur >>= 1;    ret |= (cur & 1) << 1;    return ret;}void shift(int &code){    code <<= 2;    int mm = (m + 1) << 1;    code &= ((1 << mm) - 1);}void setplug(int &cur , int y , int key){    if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);    if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);}void dpblank(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left == 0 && up == 0){  //无插头,新建联通分量            if (a[x + 1][y] && a[x][y + 1]){                setplug(aft , y - 1 , 1);                setplug(aft , y , 2);                if (y == m) shift(aft);                hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi + score[x][y].se);            }        }        else if (left && up){   // 有两个插头 ! 要删掉上插头和左插头啊            if (left == 1 && up == 1){  // ((  找到下一个对应的 ) 改成 (                int top = 0;                for (int j = y ; j <= m ; ++j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 1) ++top;                    if (plug == 2) --top;                    if (top == 0){                        setplug(aft , j , 1);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);//                hm[cur ^ 1][aft] += hm[cur].item[i].val;                hm[cur ^ 1].set(aft , hm[cur].item[i].val);            }            else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )                int top = 0;                for (int j = y - 1 ; j >= 0 ; --j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 2) ++top;                    if (plug == 1) --top;                    if (top == 0){                        setplug(aft , j , 2);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);//                hm[cur ^ 1][aft] += hm[cur].item[i].val;                hm[cur ^ 1].set(aft , hm[cur].item[i].val);            }            else if (left == 1 && up == 2){ // () 只能在最后一个格子合并                if (x == ex && y == ey){       //  如果没有连通的话加入连通                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 0);                    if (y == m) shift(aft);//                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                    hm[cur ^ 1].set(aft , hm[cur].item[i].val);                }            }            else if (left == 2 && up == 1){ //  )( 维持原来状态                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);//                hm[cur ^ 1][aft] += hm[cur].item[i].val;                hm[cur ^ 1].set(aft , hm[cur].item[i].val);            }        }        else {  // 有一个插头            if (left == 0 && up){                aft = hm[cur].item[i].key;                if (a[x][y + 1]){                    if (y == m) shift(aft);                    //hm[cur ^ 1][aft] += hm[cur].item[i].val;                    hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].se);                }                aft = hm[cur].item[i].key;                if (a[x + 1][y]){                    setplug(aft , y - 1 , up);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    //hm[cur ^ 1][aft] += hm[cur].item[i].val;                    hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi);                }            }            else if (left && up == 0){                aft = hm[cur].item[i].key;                if (a[x + 1][y]){                    if (y == m) shift(aft);//                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                    hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi);                }                aft = hm[cur].item[i].key;                if (a[x][y + 1]){                    setplug(aft , y - 1 , 0);                    setplug(aft , y , left);                    if (y == m) shift(aft);//                    hm[cur ^ 1][aft] += hm[cur].item[i].val;                    hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].se);                }            }        }    }}void dpblock(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left || up) continue;        if (y == m) shift(aft);//        hm[cur ^ 1][aft] += hm[cur].item[i].val;        hm[cur ^ 1].set(aft , hm[cur].item[i].val);    }}void output(int code){    for (int i = 0 ; i <= m ; ++i){        int ret = code % 4;        code /= 4;        if (ret == 1) putchar('(');        else if (ret == 2) putchar(')');        else putchar('#');    }}void solve(){    RD(n , m);    int line = 0;    gets(str[0]);    for (int i = 0 ; i < 2 * n + 1 ; ++i){        gets(str[i]);        if (!i) continue;        if (i & 1) line++;        if (i & 1){            for (int j = 1 ; j < m ; ++j)                score[line][j].se = str[i][j * 2] - '0';        }        else{            for (int j = 1 ; j <= m ; ++j)                score[line][j].fi = str[i][j * 2 - 1] - '0';        }    }    RST(a);    ex = n;ey = m;    for (int i = 1 ; i <= n; ++i){        for(int j = 1 ; j <= m ; ++j){            a[i][j] = 1;        }    }    int ans = INF;    int cur = 0;    hm[0].init();hm[1].init();    hm[0].set(0 , 0);    for (int i = 1 ; i <= n ; ++i)    for (int j = 1 ; j <= m ; ++j){    /**        比较喜闻乐见的 debug 方式    *///        printf("Before %d %d\n" , i , j);//        for (int k = 0 ; k < hm[cur].L ; ++k){//            output(hm[cur].item[k].key);//            printf(":%d\t" , hm[cur].item[k].val);//        }//        puts("");        hm[cur ^ 1].clear();        dpblank(i , j , cur);        cur ^= 1;//        printf("After %d %d\n" , i , j);//        for (int k = 0 ; k < hm[cur].L ; ++k){//            output(hm[cur].item[k].key);//            printf(":%d\t" , hm[cur].item[k].val);//        }//        puts("");    }    for (int i = 0 ; i < hm[cur].L ; ++i)        checkMin(ans , hm[cur].item[i].val);    printf("%d\n" , ans);}int main(){    Case = 0;    Rush solve();}

F - Tony's Tour

在有障碍的前提下,从左上走到右下的最小花费。

解法1:

加两行——

#.....

变成

#......#....

解法2:

3进制正式变成 4 进制——独立插头

struct Hashmap{    const static int HASHSIZE = 681;    const static int STATUSSIZE = 1e4 + 9;    int head[HASHSIZE];    struct hash_item{        int key;        LL val;        int next;    }item[STATUSSIZE + 1];    int L;    int getHash(int x){        return x % HASHSIZE;    }    void init(){        memset(head , -1 , sizeof(head));        L = 0;    }    void clear(){        init();return;        for (int i = 0; i < L ; ++i)            head[getHash(item[i].key)] = -1;        L = 0;    }    int contains(int x){        for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)            if (item[i].key == x)                return i;        return -1;    }    void insert(int x){        int tmp = getHash(x);        item[L].key = x;        item[L].val = 0;        item[L].next = head[tmp];        head[tmp] = L++;    }    LL& operator[] (int x){        int tmp = contains(x);        if (tmp == -1){            insert(x);            return item[L - 1].val;        }        else return item[tmp].val;    }}hm[2];const int N = 15;int n , m;int code[N] , a[N][N];int ex , ey;char str[N];void shift(int &code){    code <<= 2;    int mm = (m + 1) << 1;    code &= ((1 << mm) - 1);}int getplug(int cur , int y){    cur >>= 2 * y;    int ret = cur & 3;    return ret;}void setplug(int &cur , int y , int key){    if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);    if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);}bool canbeSinglePlug(int x , int y){    if (x == n) return y == 1 || y == m;    return false;}void UPD(LL &x , LL y){    x += y;}void dpblank(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left == 0 && up == 0){  //无插头,新建联通分量            if (a[x + 1][y] && a[x][y + 1]){                setplug(aft , y - 1 , 1);                setplug(aft , y , 2);                if (y == m) shift(aft);                UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);            }            if (canbeSinglePlug(x , y)){    // 如果能形成独立插头                if (a[x + 1][y]){                    aft = hm[cur].item[i].key;                    setplug(aft , y - 1 , 3);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }                if (a[x][y + 1]){                    aft = hm[cur].item[i].key;                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 3);                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }            }        }        else if (left && up){   // 有两个插头 ! 要删掉上插头和左插头啊            if (left == 3 && up == 3){          // 如果都是独立插头,那么只能在最后一个格子里面合并                if (x == ex && y == ey){                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }            }            else if (left == 3 || up == 3){     // 如果有一个 独立插头那么,将对应的插头改为独立插头                int other = left + up - 3;                if (other == 1){                    int top = 1;                    for (int j = y + 1; j <= m ; ++j){                        int plug = getplug(hm[cur].item[i].key , j);                        if (plug == 1) ++top;                        if (plug == 2) --top;                        if (top == 0){                            setplug(aft , j , 3);                            break;                        }                    }                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }                else if (other == 2){                    int top = 1;                    for (int j = y - 2 ; j >= 0 ; --j){                        int plug = getplug(hm[cur].item[i].key , j);                        if (plug == 2) ++top;                        if (plug == 1) --top;                        if (top == 0){                            setplug(aft , j , 3);                            break;                        }                    }                    setplug(aft , y - 1 , 0);                    setplug(aft , y , 0);                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }            }            else if (left == 1 && up == 1){  // ((  找到下一个对应的 ) 改成 (                int top = 0;                for (int j = y ; j <= m ; ++j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 1) ++top;                    if (plug == 2) --top;                    if (top == 0){                        setplug(aft , j , 1);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);            }            else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )                int top = 0;                for (int j = y - 1 ; j >= 0 ; --j){                    int plug = getplug(hm[cur].item[i].key , j);                    if (plug == 2) ++top;                    if (plug == 1) --top;                    if (top == 0){                        setplug(aft , j , 2);                        break;                    }                }                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);            }            else if (left == 1 && up == 2){ // () 只能在最后一个格子合并//                if (x == ex && y == ey){  // 不可能发生//                    setplug(aft , y - 1 , 0);//                    setplug(aft , y , 0);//                    if (y == m) shift(aft);//                    hm[cur ^ 1][aft] += hm[cur].item[i].val;//                }            }            else if (left == 2 && up == 1){ //  )( 维持原来状态                setplug(aft , y - 1 , 0);                setplug(aft , y , 0);                if (y == m) shift(aft);                UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);            }        }        else {  // 有一个插头            if (left + up == 3){                    // 如果只有一个独立插头                if (x == ex && y == ey){                //那么可以在最后一个非障碍格子中成为另一端                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }                else{                                   // 或者用下插头 或者 有插头 延续独立插头                    aft = hm[cur].item[i].key;                    if(a[x + 1][y]){                        setplug(aft , y - 1 , 3);                        setplug(aft , y , 0);                        if (y == m) shift(aft);                        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                    }                    aft = hm[cur].item[i].key;                    if(a[x][y + 1]){                        setplug(aft , y - 1 , 0);                        setplug(aft , y , 3);                        if (y == m) shift(aft);                        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                    }                }            }            else{                if (canbeSinglePlug(x , y)){            // 将当前插头封住,另一端成为独立插头                    int thisplug = left + up;                    setplug(aft , y - 1 , 0);                    setplug(aft, y , 0);                    if (thisplug == 1){                        int top = 1;                        for (int j = y + 1 ; j <= m ; ++j){                            int plug = getplug(hm[cur].item[i].key , j);                            if (plug == 1) ++top;                            if (plug == 2) --top;                            if (top == 0){                                setplug(aft , j , 3);                                break;                            }                        }                    }                    else if (thisplug == 2){                        int top = 1;                        for (int j = y - 2 ; j <= m ; ++j){                            int plug = getplug(hm[cur].item[i].key , j);                            if (plug == 2) ++top;                            if (plug == 1) --top;                            if (top == 0){                                setplug(aft , j , 3);                                break;                            }                        }                    }                    if (y == m) shift(aft);                    UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                }                aft = hm[cur].item[i].key;                if (left == 0 && up){                    aft = hm[cur].item[i].key;                    if (a[x][y + 1]){                        if (y == m) shift(aft);                        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                    }                    aft = hm[cur].item[i].key;                    if (a[x + 1][y]){                        setplug(aft , y - 1 , up);                        setplug(aft , y , 0);                        if (y == m) shift(aft);                        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                    }                }                else if (left && up == 0){                    aft = hm[cur].item[i].key;                    if (a[x + 1][y]){                        if (y == m) shift(aft);                        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                    }                    aft = hm[cur].item[i].key;                    if (a[x][y + 1]){                        setplug(aft , y - 1 , 0);                        setplug(aft , y , left);                        if (y == m) shift(aft);                        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);                    }                }            }        }    }}void dpblock(int x , int y , int cur){    int left , up;    int aft;    for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){        aft = hm[cur].item[i].key;        left = getplug(hm[cur].item[i].key , y - 1);        up = getplug(hm[cur].item[i].key , y);        if (left || up) continue;        if (y == m) shift(aft);        UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);    }}void output(int code){    for (int i = 0 ; i <= m ; ++i){        int ret = code % 4;        code /= 4;        if (ret == 1) putchar('(');        else if (ret == 2) putchar(')');        else if (ret == 3) putchar('|');        else putchar('#');    }}void solve(){    RST(a);    for (int i = 1 ; i <= n; ++i){        scanf("%s" , str);        for(int j = 1 ; j <= m ; ++j){            a[i][j] = (str[j - 1] == '.');            if (a[i][j]){                ex = i , ey = j;            }        }    }    ex = n , ey = m;    LL ans = 0;    int cur = 0;    hm[0].init();hm[1].init();    hm[0][0] = 1;    for (int i = 1 ; i <= n ; ++i)    for (int j = 1 ; j <= m ; ++j){        hm[cur ^ 1].clear();        if (a[i][j]) dpblank(i , j , cur);        else dpblock(i , j , cur);        cur ^= 1;//        printf("%d %d:\n" , i , j);               // debug 方法,输出 插头形式//        for (int k = 0 ; k < hm[cur].L ; ++k){//            output(hm[cur].item[k].key);printf(":%lld\t" , hm[cur].item[k].val);//        }//        puts("");    }    for (int i = 0 ; i < hm[cur].L ; ++i){        ans += hm[cur].item[i].val;    }    printf("%lld\n" , ans);}int main(){    Case = 0;    while(~scanf("%d%d" , &n , &m) && n && m) solve();}












原创粉丝点击