插头dp

最近学习了基于连通性的动态规划,也就是插头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 long
using 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 long
using 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 __int64
using 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 3
using 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 3
using 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 3
using 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 long
using 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 long
using 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 long
using 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;
}
/*
100
4 4
1 2 3 4
5 0 0 0
0 100 2 0
104 0 2 2

*/

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

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#define LL long long
using 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;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值