插头dp

来源:互联网 发布:2016淘宝广告位价格 编辑:程序博客网 时间:2024/04/28 05:31

最近学习了基于连通性的动态规划,也就是插头dp,刷了一些入门题。
插头dp主要解决的问题是,给定矩阵,矩阵中有些点不能到达,有些点可以到达,问经过所有可达到的点,且每个点只经过一次的回路有多少种。
学习资料有很多,相关的博客也不少,罗列一些:
cdq论文
cyendra博客
个人认为上面那篇博客讲的十分详细,值得一看。

——————————————-分割线—————————————————
插头dp的一些题,以下所用的ac代码用的全是kuangbin巨巨的模板。
HDU 1693
这是一道比较典型的题,给出矩阵,矩阵中有可达点和不可达点,求经过所有可达点一次的回路的方案数,允许一个方案中存在多条回路。既然允许存在多条回路,那么可以不用给联通块标号,code数组中只给出连通性即可。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int hash_mod=100007;const int state_size=1e6+50;const int maxc=15;int code[maxc], G[maxc][maxc];struct HASHMAP{    int head[hash_mod], state[state_size], next[state_size], st_size;    LL cnt[state_size];    void init(){        st_size=0;        memset(head, -1, sizeof head);    }    void push(int st,LL c){        int i, h=st%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(st==state[i]){            cnt[i]+=c;            return;        }        cnt[st_size]=c;        state[st_size]=st;        next[st_size]=st;        head[st]=st_size++;    }};HASHMAP hm[2];int n, m, cas;void init(){    scanf("%d%d",&n, &m);    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++)        scanf("%d",&G[i][j]);    }}int encode(int code[], int m){    int ret=0;    for(int i=0;i<=m;i++)    if(code[i]) ret|=(1<<i);    return ret;}void decode(int code[], int m, int st){    for(int i=0;i<=m;i++)        code[i]=st&(1<<i);}void shift(int code[], int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        left=code[c-1];        up=code[c];        if(left&&up){// 11            code[c-1]=code[c]=0;//influence on next row            if(c==m) shift(code, m);            hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);        }else if(left||up){            if(G[r+1][c]){                code[c-1]=1;                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }            if(G[r][c+1]){                code[c-1]=0;                code[c]=1;                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }        }else{            if(G[r+1][c]&&G[r][c+1]){                code[c-1]=code[c]=1;                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        code[c-1]=code[c]=0;        if(c==m) shift(code, m);        hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);    }}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 1);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        hm[cur^1].init();        if(G[i][j]==1){            dpblank(i, j, cur);        }else{            dpblock(i, j, cur);        }        cur^=1;    }    LL ans=0;    for(int i=0;i<hm[cur].st_size;i++)        ans+=hm[cur].cnt[i];    printf("Case %d: There are %lld ways to eat the trees.\n", ++cas, ans);}int main(){    int T;    scanf("%d",&T);    while(T--){        init();        solve();    }    return 0;}

URAL 1519
给定矩阵,其中包含可达点和不可达点,求经过所有可达点的回路的方案数。与上一题的区别是,这里必须一条回路走完所有点。
要求一条回路走完,那么必须要给联通块标号,并在code数组中给出连通性及标号,避免在没有走完所有点之前就已经形成了回路。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int hash_mod=100007;const int state_size=1e6+50;const int maxc=15;int id[maxc], code[maxc], G[maxc][maxc];struct HASHMAP{    int head[hash_mod], next[state_size], st_size;    LL state[state_size];    LL cnt[state_size];    void init(){        st_size=0;        memset(head, -1, sizeof head);    }    void push(LL st,LL c){        int i, h=st%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(st==state[i]){            cnt[i]+=c;            return;        }        cnt[st_size]=c;        state[st_size]=st;        next[st_size]=head[h];        head[h]=st_size++;    }};HASHMAP hm[2];int n, m, cas;int tx, ty;void init(){    char s[maxc];    //scanf("%d%d",&n, &m);    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++){        scanf("%s", s+1);        for(int j=1;j<=m;j++)        if(s[j]=='.'){            G[i][j]=1;            tx=i, ty=j;        }        else G[i][j]=0;    }}LL encode(int code[], int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    return ret;}void decode(int code[], int m, LL st){    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}void shift(int code[], int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        left=code[c-1];        up=code[c];        if(left&&up){// 11            if(left==up){//in the same cc                if(r==tx&&c==ty){//is the last grid                    code[c-1]=code[c]=0;//no right and down plug                    if(c==m) shift(code, m);                    hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);                }            }else{//not in the same cc                code[c-1]=code[c]=0;                for(int i=0;i<=m;i++)//combine the two cc and update code                if(code[i]==left) code[i]=up;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(G[r+1][c]){                code[c-1]=tmp;                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }            if(G[r][c+1]){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }        }else{            if(G[r+1][c]&&G[r][c+1]){                code[c-1]=code[c]=13;//assign a huge value                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        code[c-1]=code[c]=0;        if(c==m) shift(code, m);        hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);    }}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 1);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        hm[cur^1].init();        if(G[i][j]==1){            dpblank(i, j, cur);        }else{            dpblock(i, j, cur);        }        cur^=1;    }    LL ans=0;    for(int i=0;i<hm[cur].st_size;i++)        ans+=hm[cur].cnt[i];    printf("%lld\n", ans);    //printf("Case %d: There are %lld ways to eat the trees.\n", ++cas, ans);}int main(){    int T;    //scanf("%d",&T);    //while(T--){    while(~scanf("%d%d",&n, &m)){        init();        solve();    }    //}    return 0;}

FZU 1977
给定矩阵,其中有不可达点,必达点(回路中必须经过的点),选达点(回路中可以经过也可以不经过的点),求经过所有必达点的回路的方案数,方案中只能有一条回路。
这里加入了选达点,这意味着我们在考虑一个点时,如果它没有与之前的点联通,我们不仅需要考虑它同时向下和向右伸出插头,还要考虑它没有任何插头的情况并加入到hash map中。
输出用__int64,long long会WA。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#include<limits.h>#define LL __int64using namespace std;const int hash_mod=100007;const int state_size=5e5+50;const int maxc=15;int id[maxc], code[maxc], G[maxc][maxc];struct HASHMAP{    int head[hash_mod], next[state_size], st_size;    LL state[state_size];    LL cnt[state_size];    void init(){        st_size=0;        memset(head, -1, sizeof head);    }    void push(LL st,LL c){        int i, h=st%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(st==state[i]){            cnt[i]+=c;            return;        }        cnt[st_size]=c;        state[st_size]=st;        next[st_size]=head[h];        head[h]=st_size++;    }};HASHMAP hm[2];int n, m, cas;int isend;int tx, ty;void init(){    char s[maxc];    scanf("%d%d",&n, &m);    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++){        scanf("%s", s+1);        for(int j=1;j<=m;j++)        if(s[j]=='X'){            G[i][j]=0;        }else if(s[j]=='O'){            G[i][j]=1;            tx=i, ty=j;        }else{            G[i][j]=2;        }    }}LL encode(int code[], int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    ret<<=1;    ret|=isend;    return ret;}void decode(int code[], int m, LL st){    isend=st&1;    st>>=1;    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}void shift(int code[], int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        left=code[c-1];        up=code[c];        if(isend){            if(left||up||G[r][c]==1) continue;        }        if(left&&up){// 11            if(left==up){//in the same cc                code[c-1]=code[c]=0;//no right and down plug                isend=1;                //if(c==m) shift(code, m);                hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);            }else{//not in the same cc                code[c-1]=code[c]=0;                for(int i=0;i<=m;i++)//combine the two cc and update code                if(code[i]==left) code[i]=up;                //if(c==m) shift(code, m);                hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(G[r+1][c]){                code[c-1]=tmp;                code[c]=0;                //if(c==m) shift(code, m);                hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);            }            if(G[r][c+1]){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);            }        }else{            if(G[r+1][c]&&G[r][c+1]){                code[c-1]=code[c]=13;//assign a huge value                hm[cur^1].push(encode(code, m), hm[cur].cnt[i]);            }            if(G[r][c]==2){                code[c-1]=code[c]=0;                //if(c==m) shift(code, m);                hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        code[c-1]=code[c]=0;        //if(c==m) shift(code, m);        hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);    }}void solve(){    int cur=0;    LL ans=0;    hm[cur].init();    hm[cur].push(0, 1);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        hm[cur^1].init();        if(G[i][j]){            dpblank(i, j, cur);        }else{            dpblock(i, j, cur);        }        cur^=1;    }    for(int i=0;i<hm[cur].st_size;i++)        ans+=hm[cur].cnt[i];    //printf("%lld\n", ans);    printf("Case %d: %I64d\n", ++cas, ans);}int main(){    int T;    scanf("%d",&T);    while(T--){    //while(~scanf("%d%d",&n, &m)){        init();        solve();    }    //}    return 0;}

HDU 1964
这道题是求一条权值最大的回路。把hash map中的push函数中的cnt加操作改为取大值即可。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long long#define UP 0#define RIGHT 1#define DOWN 2#define LEFT 3using namespace std;const int hash_mod=100007;const int max_state=1e6+50;const int maxc=15;struct HASHMAP{    int head[hash_mod], next[max_state];    LL state[max_state];    int size;    int cost[max_state];    void init(){        size=0;        memset(head, -1, sizeof(head));    }    void push(LL x,int c){        int i, h=x%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(state[i]==x){            cost[i]=min(cost[i], c);            return;        }        state[size]=x;        cost[size]=c;        next[size]=head[h];        head[h]=size++;    }};HASHMAP hm[2];int n, m;int id[maxc];int code[maxc];char s[maxc*2][maxc*2];void decode(int code[],int m,LL st){    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}LL encode(int code[], int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    return ret;}void shift(int code[],int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}int getcost(int r,int c,int d){    int x=2*r-1, y=2*c-1;    int ret=0;    if(d==UP&&s[x-1][y]!='#') ret+=s[x-1][y]-'0';    if(d==DOWN&&s[x+1][y]!='#') ret+=s[x+1][y]-'0';    if(d==LEFT&&s[x][y-1]!='#') ret+=s[x][y-1]-'0';    if(d==RIGHT&&s[x][y+1]!='#') ret+=s[x][y+1]-'0';    return ret;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        int cost=hm[cur].cost[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){            if(left==up){//in the same cc                if(r==n&&c==m){                    code[c-1]=code[c]=0;                    if(c==m) shift(code, m);                    hm[cur^1].push(encode(code, m), cost);                }            }else{//not in the same cc                code[c-1]=code[c]=0;                for(int i=0;i<=m;i++)//make then in the same cc                if(code[i]==left) code[i]=up;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cost);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(c+1<=m){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, m), cost+getcost(r, c, RIGHT));            }            if(r+1<=n){                code[c-1]=tmp;                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cost+getcost(r, c, DOWN));            }        }else{            if(r+1<=n&&c+1<=m){                code[c-1]=code[c]=13;                hm[cur^1].push(encode(code, m), cost+getcost(r, c, RIGHT)+getcost(r, c, DOWN));            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cost=hm[cur].cost[i];        decode(code, m, st);        code[c-1]=code[c]=0;        hm[cur^1].push(encode(code, m), cost);    }}void init(){    scanf("%d%d",&n, &m); getchar();    for(int i=0;i<2*n+1;i++)        gets(s[i]);}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 0);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            hm[cur^1].init();            dpblank(i, j, cur);            cur^=1;        }    }    int ans=0x3f3f3f3f;    for(int i=0;i<hm[cur].size;i++)        ans=min(ans, hm[cur].cost[i]);    printf("%d\n", ans);}int main(){    int T;    scanf("%d", &T);    while(T--){        init();        solve();    }    return 0;}

HDU 3377
找一条从左上角到右下角的权值和最大的路径。
把起点和终点特殊处理即可,因为他们只有一个插头,其他点都有两个插头。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long long#define UP 0#define RIGHT 1#define DOWN 2#define LEFT 3using namespace std;const int hash_mod=100007;const int max_state=1e6+50;const int maxc=15;struct HASHMAP{    int head[hash_mod], next[max_state];    LL state[max_state];    int size;    int cost[max_state];    void init(){        size=0;        memset(head, -1, sizeof(head));    }    void push(LL x,int c){        int i, h=x%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(state[i]==x){            cost[i]=max(cost[i], c);            return;        }        state[size]=x;        cost[size]=c;        next[size]=head[h];        head[h]=size++;    }};HASHMAP hm[2];int n, m, cas;int id[maxc];int code[maxc];int G[maxc][maxc];void decode(int code[],int m,LL st){    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}LL encode(int code[], int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    return ret;}void shift(int code[],int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}int getcost(int r,int c,int d){    int x=r, y=c;    int ret=0;    if(d==UP&&x-1>=1) ret+=G[x-1][y];    if(d==DOWN&&x+1<=n) ret+=G[x+1][y];    if(d==LEFT&&y-1>=1) ret+=G[x][y-1];    if(d==RIGHT&&y+1<=m) ret+=G[x][y+1];    return ret;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        int cost=hm[cur].cost[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){            if(r==n&&c==m) continue;            if(left==up){//in the same cc                continue;            }else{//not in the same cc                code[c-1]=code[c]=0;                for(int i=0;i<=m;i++)//make then in the same cc                if(code[i]==left) code[i]=up;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cost+G[r][c]);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(r==n&&c==m){                code[c-1]=code[c]=0;                shift(code, m);                hm[cur^1].push(encode(code, m), cost+G[r][c]);                continue;                puts("Infinity");            }            if(c+1<=m){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, m), cost+G[r][c]);            }            if(r+1<=n){                code[c-1]=tmp;                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cost+G[r][c]);            }        }else{            if(r==n&&c==m) continue;            if(r+1<=n&&c+1<=m){                code[c-1]=code[c]=13;                hm[cur^1].push(encode(code, m), cost+G[r][c]);            }            code[c-1]=code[c]=0;            if(c==m) shift(code, m);            hm[cur^1].push(encode(code, m), cost);        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cost=hm[cur].cost[i];        decode(code, m, st);        code[c-1]=code[c]=0;        hm[cur^1].push(encode(code, m), cost);    }}void init(){    //scanf("%d%d",&n, &m); getchar();    //for(int i=0;i<2*n+1;i++)    //    gets(s[i]);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    scanf("%d", &G[i][j]);}void solve(){    if(n==1&&m==1){        printf("Case %d: %d\n",++cas, G[1][1]);        return;    }    int ans=-0x3f3f3f3f;    int cur=0;    memset(code, 0, sizeof(code));    hm[cur].init();    if(2<=m){        code[0]=0, code[1]=1;        if(m==1) shift(code, m);        hm[cur].push(encode(code, m), G[1][1]);    }    if(2<=n){        code[0]=1, code[1]=0;        if(m==1) shift(code, m);        hm[cur].push(encode(code, m), G[1][1]);    }    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++)        if(i+j>2){            hm[cur^1].init();            dpblank(i, j, cur);            cur^=1;        }    }    for(int i=0;i<hm[cur].size;i++){        ans=max(ans, hm[cur].cost[i]);    }    printf("Case %d: %d\n",++cas, ans);}int main(){    int T;    //scanf("%d", &T);    while(~scanf("%d%d",&n, &m)){        init();        solve();    }    return 0;}

POJ 1739
求左下角,注意是左下角,到右下角的经过所有可达点路径的条数。
在原图末尾再添两行,并把其中第一行的中间设为不可达,其他均可达,然后求经过所有可达点的回路数即可。
即在末尾加
.*****.(m-2个*)
…….(m个.)

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long long#define UP 0#define RIGHT 1#define DOWN 2#define LEFT 3using namespace std;const int hash_mod=100007;const int max_state=1e6+50;const int maxc=15;struct HASHMAP{    int head[hash_mod], next[max_state];    LL state[max_state];    int size;    LL cost[max_state];    void init(){        size=0;        memset(head, -1, sizeof(head));    }    void push(LL x,LL c){        int i, h=x%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(state[i]==x){            cost[i]+=c;            return;        }        state[size]=x;        cost[size]=c;        next[size]=head[h];        head[h]=size++;    }};HASHMAP hm[2];int n, m, cas;int id[maxc];int code[maxc];int G[maxc][maxc];char s[maxc][maxc];void decode(int code[],int m,LL st){    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}LL encode(int code[], int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    return ret;}void shift(int code[],int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}int getcost(int r,int c,int d){    int x=r, y=c;    int ret=0;    if(d==UP&&x-1>=1) ret+=G[x-1][y];    if(d==DOWN&&x+1<=n) ret+=G[x+1][y];    if(d==LEFT&&y-1>=1) ret+=G[x][y-1];    if(d==RIGHT&&y+1<=m) ret+=G[x][y+1];    return ret;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cost=hm[cur].cost[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){            if(left==up){//in the same cc                if(r==n&&c==m){                    code[c-1]=code[c]=0;                    shift(code, m);                    hm[cur^1].push(encode(code, m), cost);                }            }else{//not in the same cc                code[c-1]=code[c]=0;                for(int i=0;i<=m;i++)//make then in the same cc                if(code[i]==left) code[i]=up;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cost);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(G[r][c+1]){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, m), cost);            }            if(G[r+1][c]){                code[c-1]=tmp;                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cost);            }        }else{            if(G[r+1][c]&&G[r][c+1]){                code[c-1]=code[c]=13;                hm[cur^1].push(encode(code, m), cost);            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cost=hm[cur].cost[i];        decode(code, m, st);        code[c-1]=code[c]=0;        if(c==m) shift(code, m);        hm[cur^1].push(encode(code, m), cost);    }}void init(){    //scanf("%d%d",&n, &m); getchar();    //for(int i=0;i<2*n+1;i++)    //    gets(s[i]);    for(int i=1;i<=n;i++)    scanf("%s", s[i]+1);    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)        G[i][j]=s[i][j]=='.';    G[n+1][1]=1; G[n+1][m]=1;    for(int j=1;j<=m;j++)        G[n+2][j]=1;    n+=2;}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 1);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            hm[cur^1].init();            if(G[i][j]) dpblank(i, j, cur);            else dpblock(i, j, cur);            cur^=1;        }    }    LL ans=0;    for(int i=0;i<hm[cur].size;i++)        ans+=hm[cur].cost[i];    //printf("Case %d: %d\n",++cas, ans);    printf("%lld\n", ans);}int main(){    int T;    //scanf("%d", &T);    while(~scanf("%d%d",&n, &m)){        if(n==0&&m==0) break;        init();        solve();    }    return 0;}

POJ 3133
2与2通过一条路径相连,3与3通过一条路径相连,并且这两条路径不相交,求路径权值和最小值。
显然在这里联通块只有两个,2所在的和3所在的,再加上处理路径时的方法,路径端点即2和3所在的位置只往外伸出一个插头即可。

#include<math.h>#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#define LL long longusing namespace std;const int max_state=1e6+50;const int hash_mod=1e5+7;const int maxc=15;const int Inf=0x3f3f3f3f;struct HASHMAP{    LL state[max_state], cnt[max_state];    int head[hash_mod], next[max_state];    int size;    void init(){        size=0;        memset(head, -1, sizeof head);    }    void push(LL x,LL c){        int i, h=x%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(state[i]==x){            cnt[i]=min(cnt[i], c);            return;        }        state[size]=x;        cnt[size]=c;        next[size]=head[h];        head[h]=size++;    }};HASHMAP hm[2];int n, m;int id[maxc], code[maxc];int G[maxc][maxc];void decode(int code[], int m, LL st){    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}LL encode(int code[], int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        //if(id[code[i]]==-1) id[code[i]]=++cnt;        //code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    return ret;}void shift(int code[], int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}bool can(int x,int y){    return x==1||x==y;}void dpblank(int r, int c, int cur){    int left, up;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cnt=hm[cur].cnt[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){            if(left==up){                code[c-1]=code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt+1);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(can(G[r][c+1],tmp)){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, m), cnt+1);            }            if(can(G[r+1][c], tmp)){                code[c-1]=tmp;                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt+1);            }        }else{            if(can(G[r][c+1],2)&&can(G[r+1][c],2)){                code[c-1]=code[c]=2;                hm[cur^1].push(encode(code, m), cnt+1);            }            if(can(G[r][c+1],3)&&can(G[r+1][c],3)){                code[c-1]=code[c]=3;                hm[cur^1].push(encode(code, m), cnt+1);            }            code[c-1]=code[c]=0;            if(c==m) shift(code, m);            hm[cur^1].push(encode(code, m), cnt);        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cnt=hm[cur].cnt[i];        decode(code, m, st);        code[c-1]=code[c]=0;        if(c==m) shift(code, m);        hm[cur^1].push(encode(code, m), cnt);    }}void dplimit(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cnt=hm[cur].cnt[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){            continue;        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(G[r][c]==tmp){                code[c-1]=code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt+1);            }        }else{            if(can(G[r][c+1], G[r][c])){                code[c-1]=0;                code[c]=G[r][c];                hm[cur^1].push(encode(code, m), cnt+1);            }            if(can(G[r+1][c], G[r][c])){                code[c-1]=G[r][c];                code[c]=0;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt+1);            }        }    }}void init(){    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++){            scanf("%d", &G[i][j]);            if(G[i][j]==1) G[i][j]=0;            else if(G[i][j]==0) G[i][j]=1;        }}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 0);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        hm[cur^1].init();        if(G[i][j]==2||G[i][j]==3){            dplimit(i, j, cur);        }else if(G[i][j]){            dpblank(i, j, cur);        }else{            dpblock(i, j, cur);        }        cur^=1;//        for(int k=0;k<hm[cur].size;k++){//            decode(code, m, hm[cur].state[k]);//            printf("row=%d line=%d\n", i, j);//            for(int l=0;l<=m;l++)//                printf("%d%c", code[l], l==m?'\n':' ');//            printf("%lld %lld\n", hm[cur].state[k], hm[cur].cnt[k]);//        }    }    LL ans=Inf;//    printf("size=%d\n",hm[cur].size);    for(int i=0;i<hm[cur].size;i++)        ans=min(ans, hm[cur].cnt[i]);    printf("%lld\n", ans<Inf?ans-2:0);}int main(){    while(~scanf("%d%d",&n ,&m)){        if(n==0&&m==0) break;        init();        solve();    }    return 0;}

ZOJ 3466
n*8的图形,并且由正六边形构成,给出不可达点,求经过所有可达点一次的回路的条数。
其实这个图形转个90度看解决起来更方便,每个位置可能引出插头的方向有3个,右,左下,右下,shift操作的时候注意行与行并不是对齐的,偶数行转奇数行才要shift两格,而奇数行转偶数行不需要shift。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#define LL long longusing namespace std;const int max_size=1e6+50;const int hash_mod=1e5+7;const int maxc=15;struct HASHMAP{    int size;    int head[hash_mod], next[max_size];    LL state[max_size], cnt[max_size];    void init(){        size=0;        memset(head, -1, sizeof head);    }    void push(LL st,LL c){        int i, h=st%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(state[i]==st){            cnt[i]+=c;            return;        }        state[size]=st;        cnt[size]=c;        next[size]=head[h];        head[h]=size++;    }};HASHMAP hm[2];int code[2*maxc], id[maxc];int n, m;int G[maxc][maxc];void decode(int code[],int m,LL st){    for(int i=m;i>=0;i--){        code[i]=st&1;        st>>=1;    }}LL encode(int code[],int m){    LL ret=0;    for(int i=0;i<=m;i++){        //if(id[code[i]]==-1) id[code[i]]=++cnt;        //code[i]=id[code[i]];        ret<<=1;        ret|=code[i];    }    return ret;}void shift(int code[],int m){//even->odd && c==m    for(int i=m;i>1;i--)        code[i]=code[i-2];    code[0]=code[1]=0;}void dpblank(int r,int c,int cur){    int left, up, up2;    int t1, t2;    if(r%2) t1=c, t2=c+1;    else t1=c-1, t2=c;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cnt=hm[cur].cnt[i];        decode(code, 2*m, st);        left=code[2*c-2];        up=code[2*c-1];        up2=code[2*c];        if(left&&up&&up2){            continue;        }else if((left&&up)||(left&&up2)||(up&&up2)){            code[2*c]=code[2*c-1]=code[2*c-2]=0;            if(c==m&&r%2) shift(code, 2*m);            hm[cur^1].push(encode(code, 2*m), cnt);        }else if(left||up||up2){            if(G[r][c+1]){                code[2*c]=1;                code[2*c-2]=code[2*c-1]=0;                hm[cur^1].push(encode(code, 2*m), cnt);            }            if(G[r+1][t1]){                code[2*c-2]=1;                code[2*c]=code[2*c-1]=0;                if(c==m&&r%2) shift(code, 2*m);                hm[cur^1].push(encode(code, 2*m), cnt);            }            if(G[r+1][t2]){                code[2*c-1]=1;                code[2*c]=code[2*c-2]=0;                if(c==m&&r%2) shift(code, 2*m);                hm[cur^1].push(encode(code, 2*m), cnt);            }        }else{            if(G[r][c+1]&&G[r+1][t1]){                code[2*c]=code[2*c-2]=1;                code[2*c-1]=0;                hm[cur^1].push(encode(code, 2*m), cnt);            }            if(G[r][c+1]&&G[r+1][t2]){                code[2*c]=code[2*c-1]=1;                code[2*c-2]=0;                hm[cur^1].push(encode(code, 2*m), cnt);            }            if(G[r+1][t1]&&G[r+1][t2]){                code[2*c]=0;                code[2*c-1]=code[2*c-2]=1;                if(c==m&&r%2) shift(code, 2*m);                hm[cur^1].push(encode(code, 2*m), cnt);            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        LL cnt=hm[cur].cnt[i];        decode(code, 2*m, st);        code[2*c-2]=code[2*c-1]=code[2*c]=0;        if(r%2&&c==m) shift(code, 2*m);        hm[cur^1].push(encode(code, 2*m), cnt);    }}void init(){    char s[5];    memset(G, 0, sizeof G);    for(int i=1;i<=8;i++)    for(int j=1;j<=n;j++) G[i][j]=1;    for(int i=0;i<m;i++){        scanf("%s", s);        int r=s[0]-'A'+1;        int c=s[1]-'A'+1;        G[c][r]=0;    }    m=n; n=8;}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 1);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        hm[cur^1].init();        if(G[i][j]) dpblank(i, j, cur);        else dpblock(i, j, cur);        cur^=1;//        for(int k=0;k<hm[cur].size;k++)//            printf("r=%d c=%d state=%lld cnt=%lld\n", i, j, hm[cur].state[k], hm[cur].cnt[k]);    }    LL ans=0;    for(int i=0;i<hm[cur].size;i++)    if(hm[cur].state[i]==0) ans+=hm[cur].cnt[i];    printf("%lld\n", ans);}int main(){    while(~scanf("%d%d",&n, &m)){        init();        solve();    }    return 0;}

ZOJ 3213
给出矩阵,不限起点,不限终点,找出一条权值和最大的路径,路径上每个点只能经过一次。额外加一个标记位,来记录端点的个数,当端点个数不足2时,可以考虑把当前点作为端点。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int hash_mod=3e4+7;const int state_size=1e6+50;const int maxc=15;int id[maxc], code[maxc], G[maxc][maxc];struct HASHMAP{    int head[hash_mod], next[state_size], st_size;    int state[state_size];    int cnt[state_size];    void init(){        st_size=0;        memset(head, -1, sizeof head);    }    void push(int st,int c){        int i, h=st%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(st==state[i]){            cnt[i]=max(cnt[i], c);            return;        }        cnt[st_size]=c;        state[st_size]=st;        next[st_size]=head[h];        head[h]=st_size++;    }};HASHMAP hm[2];int n, m, nums;int encode(int code[], int m){    int ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    ret<<=3;    ret|=nums;    return ret;}void decode(int code[], int m, int st){    nums=st&7;    st>>=3;    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}void shift(int code[], int m){    for(int i=m;i>0;i--)        code[i]=code[i-1];    code[0]=0;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].st_size;i++){        int cnt=hm[cur].cnt[i];        int st=hm[cur].state[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){// 11            if(left!=up){//not in the same cc                code[c-1]=code[c]=0;                for(int j=0;j<=m;j++)//combine the two cc and update code                if(code[j]==left) code[j]=up;                hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]);            }        }else if(left||up){            int tmp;            if(left) tmp=left;            else tmp=up;            if(G[r+1][c]){                code[c-1]=tmp;                code[c]=0;                hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]);            }            if(G[r][c+1]){                code[c-1]=0;                code[c]=tmp;                hm[cur^1].push(encode(code, m), cnt+G[r][c]);            }            if(nums<2){                nums++;                code[c-1]=code[c]=0;                hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]);            }        }else{            code[c-1]=code[c]=0;            hm[cur^1].push(encode(code, c==m?m-1:m), cnt);            if(G[r+1][c]&&G[r][c+1]){                code[c-1]=code[c]=13;//assign a huge value                hm[cur^1].push(encode(code, m), cnt+G[r][c]);            }            if(nums<2){                nums++;                if(G[r+1][c]){                    code[c-1]=13;                    code[c]=0;                    hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]);                }                if(G[r][c+1]){                    code[c-1]=0;                    code[c]=13;                    hm[cur^1].push(encode(code, m), cnt+G[r][c]);                }            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].st_size;i++){        decode(code, m, hm[cur].state[i]);        code[c-1]=code[c]=0;        hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]);    }}void init(){    char s[maxc];    scanf("%d%d",&n, &m);    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        scanf("%d", &G[i][j]);}void solve(){    int cur=0;    int ans=0;    hm[cur].init();    hm[cur].push(0, 0);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        ans=max(ans, G[i][j]);        hm[cur^1].init();        if(G[i][j]){            dpblank(i, j, cur);        }else{            dpblock(i, j, cur);        }        cur^=1;    }    for(int i=0;i<hm[cur].st_size;i++){        ans=max(ans, hm[cur].cnt[i]);    }    printf("%d\n", ans);}int main(){    int T;    scanf("%d",&T);    while(T--){        init();        solve();    }    return 0;}/*1004 41 2 3 45 0 0 00 100 2 0104 0 2 2*/

HDU 4285
给出矩阵,可达点,不可达点,求只用K条回路恰经过所有点一次的方案数。额外加一个标志位,记录当前回路数,相同联通块合并时回路数加1。

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#define LL long longusing namespace std;const int max_size=1e6+50;const int hash_mod=1e5+7;const int maxc=15;const int mod=1e9+7;struct HASHMAP{    int size;    LL state[max_size];    int cnt[max_size];    int head[hash_mod], next[max_size];    void init(){        size=0;        memset(head, -1, sizeof head);    }    void push(LL st, int c){        int i, h=st%hash_mod;        for(i=head[h];i!=-1;i=next[i])        if(state[i]==st){            cnt[i]=(cnt[i]+c)%mod;            return;        }        state[size]=st;        cnt[size]=c%mod;        next[size]=head[h];        head[h]=size++;    }};HASHMAP hm[2];int id[maxc], code[maxc];int n, m, K, nums;int G[maxc][maxc];LL encode(int code[],int m){    LL ret=0;    int cnt=0;    memset(id, -1, sizeof id);    id[0]=0;    for(int i=0;i<=m;i++){        if(id[code[i]]==-1) id[code[i]]=++cnt;        code[i]=id[code[i]];        ret<<=3;        ret|=code[i];    }    ret<<=5;    ret|=nums;    return ret;}void decode(int code[],int m,LL st){    nums=st&31;    st>>=5;    for(int i=m;i>=0;i--){        code[i]=st&7;        st>>=3;    }}void shift(int code[],int m){    for(int i=m;i>0;i--){        code[i]=code[i-1];    }    code[0]=0;}void dpblank(int r,int c,int cur){    int left, up;    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        int cnt=hm[cur].cnt[i];        decode(code, m, st);        left=code[c-1];        up=code[c];        if(left&&up){            if(left==up){                if(nums>=K) continue;                int plugs=0;                for(int j=0;j<c-1;j++)                if(code[j]) plugs++;                if(plugs&1) continue;                code[c-1]=code[c]=0;                nums++;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt);            }else{                code[c-1]=code[c]=0;                for(int j=0;j<=m;j++)                if(code[j]==left) code[j]=up;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt);            }        }else if(left||up){            int tmp=max(left, up);            if(G[r][c+1]){                code[c]=tmp;                code[c-1]=0;                hm[cur^1].push(encode(code, m), cnt);            }            if(G[r+1][c]){                code[c]=0;                code[c-1]=tmp;                if(c==m) shift(code, m);                hm[cur^1].push(encode(code, m), cnt);            }        }else{            if(G[r][c+1]&&G[r+1][c]){                code[c-1]=code[c]=13;                hm[cur^1].push(encode(code, m), cnt);            }        }    }}void dpblock(int r,int c,int cur){    for(int i=0;i<hm[cur].size;i++){        LL st=hm[cur].state[i];        int cnt=hm[cur].cnt[i];        decode(code, m, st);        code[c-1]=code[c]=0;        if(c==m) shift(code, m);        hm[cur^1].push(encode(code, m), cnt);    }}void init(){    char s[maxc];    scanf("%d%d%d", &n, &m, &K);    memset(G, 0, sizeof G);    for(int i=1;i<=n;i++){        scanf("%s", s+1);        for(int j=1;j<=m;j++)        if(s[j]=='.') G[i][j]=1;    }}void solve(){    int cur=0;    hm[cur].init();    hm[cur].push(0, 1);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        hm[cur^1].init();        if(G[i][j]) dpblank(i, j, cur);        else dpblock(i, j, cur);        cur^=1;    }    int ans=0;    for(int i=0;i<hm[cur].size;i++){        decode(code, m, hm[cur].state[i]);        if(nums==K) ans=(ans+hm[cur].cnt[i])%mod;    }    printf("%d\n", ans);}int main(){    int T;    scanf("%d", &T);    while(T--){        init();        solve();    }    return 0;}
原创粉丝点击