【Learning】适妞来学 插头 dp

极其仰慕 邝斌 巨巨!!!!!! 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();
}












  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值