[bzoj2331][SCOI2011]地板【插头dp】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=2331
【题解】
  可以用插头dp的方式表示状态。
  每一位用一个三进制位表示,0表示没有木块向该方向连通,1表示有木块,且还未拐弯。2表示有木块并且拐弯了。
  时间复杂度O(NM22M+2),N>M
  

/* --------------
    user Vanisher
    problem bzoj-2331 
----------------*/
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    P       20110520
# define    N       110
# define    T       11
using namespace std;
int read(){
    int tmp=0, fh=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    return tmp*fh;
}
vector <int> g[2],f[2];
int n,m,f1,f2,nex[N],now[N],h[1<<(2*T)],lim;
char mp[N][N],ne[N][N];
int getnum(){
    int cnt=0;
    for (int i=0; i<=m; i++) cnt=cnt+(nex[i]<<(i*2));
    return cnt;
}
void join(int num){
    int tmp=getnum();
    if (h[tmp]==-1){
        h[tmp]=g[f2].size();
        g[f2].push_back(tmp);
        f[f2].push_back(num);
    }
    else f[f2][h[tmp]]=(f[f2][h[tmp]]+num)%P;
}
int main(){
    n=read(), m=read();
    for (int i=0; i<n; i++)
        scanf("\n%s",mp[i]);
    if (n<m){
        for (int i=0; i<n; i++)
            for (int j=0; j<m; j++)
                ne[j][i]=mp[i][j];
        swap(n,m);
        for (int i=0; i<n; i++)
            for (int j=0; j<m; j++)
                mp[i][j]=ne[i][j];
    }
    f1=0, f2=1, lim=1<<(2*m+2);
    g[f1].push_back(0); f[f1].push_back(1);
    memset(h,-1,sizeof(h));
    for (int i=0; i<n; i++){
        for (int j=0; j<m; j++){
            for (unsigned k=0; k<g[f1].size(); k++){
                int tmp=g[f1][k], num=f[f1][k]; 
                if (tmp>=lim) continue;
                for (int t=0; t<=m; t++) now[t]=nex[t]=(tmp>>(t*2))&3;
                if (mp[i][j]=='*'){
                    if (now[j]==0&&now[j+1]==0) join(num);
                }
                else {
                    if (now[j]==0&&now[j+1]==0){
                        nex[j]=2, nex[j+1]=2; join(num);
                        nex[j]=1, nex[j+1]=0; join(num);
                        nex[j]=0, nex[j+1]=1; join(num);
                    }
                    if (now[j]!=0&&now[j+1]==0){
                        if (now[j]==1){
                            nex[j]=2, nex[j+1]=0; join(num);
                            nex[j]=0, nex[j+1]=1; join(num);
                        }
                        else {
                            nex[j]=0, nex[j+1]=2; join(num);
                            nex[j]=0, nex[j+1]=0; join(num);
                        }
                    }
                    if (now[j]==0&&now[j+1]!=0){
                        if (now[j+1]==1){
                            nex[j]=1, nex[j+1]=0; join(num);
                            nex[j]=0, nex[j+1]=2; join(num);
                        }
                        else {
                            nex[j]=2, nex[j+1]=0; join(num);
                            nex[j]=0, nex[j+1]=0; join(num);
                        }
                    }
                    if (now[j]==1&&now[j+1]==1){
                        nex[j]=0, nex[j+1]=0; join(num);
                    }
                }
            }
            g[f1].clear(), f[f1].clear();
            for (unsigned k=0; k<g[f2].size(); k++) h[g[f2][k]]=-1;
            swap(f1,f2);
        }
        for (unsigned k=0; k<g[f1].size(); k++)     g[f1][k]<<=2;
    }
    for (unsigned i=0; i<g[f1].size(); i++)
        if (g[f1][i]==0){
            printf("%d\n",f[f1][i]);
            return 0;
        }
    printf("0\n");
    return 0;
}
posted @ 2018-04-17 18:47  Vanisher  阅读(95)  评论(0编辑  收藏  举报