码迷,mamicode.com
首页 > 其他好文 > 详细

插头dp

时间:2016-04-25 22:36:06      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了。

 

bzoj2331 地板

题目大意:用L型铺地n*m,有一些格子不能铺,求方案数。

思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移。

注意:(1)按四进制好写;

   (2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组。

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 105
#define M 200000
#define uu 50000
#define pp 20110520
using namespace std;
int ai[N][N],fi[2][M]={0},point[uu],next[M],en[M],ha[2][M],tot[2],bt[N],
    nm,n,m,cur,la;
int in(){
    char ch=getchar();
    while(ch!=_&&ch!=*) ch=getchar();
    return ch==*;}
void add(int s,int gi){
    int i,x=s%uu;
    for (i=point[x];i;i=next[i])
        if (ha[cur][en[i]]==s){
            fi[cur][en[i]]=(fi[cur][en[i]]+gi)%pp;
            return;
        }
    ha[cur][++tot[cur]]=s;fi[cur][tot[cur]]=gi;
    next[++nm]=point[x];point[x]=nm;en[nm]=tot[cur];}
void dp(){
    int i,j,k,p,q,s,gi,ji;cur=1;la=0;
    tot[cur]=1;en[1]=0;ji=3;
    ha[cur][1]=0;fi[cur][1]=1;
    for (i=0;i<N;++i) bt[i]=i<<1;
    for (i=1;i<=n;++i){
        for (j=1;j<=tot[cur];++j) ha[cur][j]=(ha[cur][j]<<2)&((1<<(bt[m+1]+1))-1);
        for (j=1;j<=m;++j){
            cur^=1;la^=1;
            tot[cur]=nm=0;
            memset(fi[cur],0,sizeof(fi[cur]));
            memset(point,0,sizeof(point));
            for (k=tot[la];k;--k){
                s=ha[la][k];gi=fi[la][k];
                if (!gi) continue;
                p=(s>>bt[j-1])&ji;
                q=(s>>bt[j])&ji;
                if (ai[i][j]){
                    if (!p&&!q) add(s,gi);
                }else if (!p&&!q){
                    if (!ai[i+1][j]) add(s+(1<<bt[j-1]),gi);
                    if (!ai[i][j+1]) add(s+(1<<bt[j]),gi);
                    if (!ai[i+1][j]&&!ai[i][j+1]) add(s+(1<<(bt[j-1]+1))+(1<<(bt[j]+1)),gi);
                }else if (!p){
                    s-=(1<<bt[j])*q;
                    if (q==1){
                        if (!ai[i][j+1]) add(s+(1<<(bt[j]+1)),gi);
                        if (!ai[i+1][j]) add(s+(1<<bt[j-1]),gi);
                    }else{
                        add(s,gi);
                        if (!ai[i+1][j]) add(s+(1<<(bt[j-1]+1)),gi);
                    }
                }else if (!q){
                    s-=(1<<bt[j-1])*p;
                    if (p==1){
                        if (!ai[i][j+1]) add(s+(1<<bt[j]),gi);
                        if (!ai[i+1][j]) add(s+(1<<(bt[j-1]+1)),gi);
                    }else{
                        add(s,gi);
                        if (!ai[i][j+1]) add(s+(1<<(bt[j]+1)),gi);
                    }
                }else if (p==1&&q==1){
                    s-=(1<<bt[j-1])+(1<<bt[j]);
                    add(s,gi);
                }
            }
        }
    }
}
int main(){
    int i,j;scanf("%d%d",&n,&m);
    memset(ai,127,sizeof(ai));
    if (n<m){
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j) ai[j][i]=in();
        swap(n,m);
    }else
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j) ai[i][j]=in();
    dp();printf("%d\n",fi[cur][1]);
}
View Code

 

插头dp

标签:

原文地址:http://www.cnblogs.com/Rivendell/p/5432911.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!