P5056 【模板】插头dp

传送门

完了……好像……已经把插头dp全都忘光了……
可以去看看这篇blog
为了卡常变得丧心病狂的代码

//minamoto
#include<bits/stdc++.h>
#define ll long long
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int N=25,P=23333,M=40005;
struct MAIN{
    int n,m;char s[N];bool mp[N][N];
    int cnt[2],cur,vis[2][M],hsh[P+5],ex,ey,S,l,r,dt,val;
    ll dp[2][M],ans;
    void insert(R int S,R ll sum){
        R int pos=S%P;
        while(hsh[pos]){
            if(vis[cur][hsh[pos]]==S)return (void)(dp[cur][hsh[pos]]+=sum);
            pos=(pos+1)%P;
        }hsh[pos]=++cnt[cur],vis[cur][hsh[pos]]=S,dp[cur][hsh[pos]]=sum;
    }
    MAIN(){
        scanf("%d%d",&n,&m);
        fp(i,1,n){
            scanf("%s",s+1);
            fp(j,1,m)if(s[j]=='.')mp[i][j]=1,ex=i,ey=j;
        }
        dp[0][1]=cnt[0]=1;
        fp(i,1,n){
            fp(j,1,m){
                cnt[cur^=1]=0;memset(hsh,0,sizeof(hsh));
                fp(k,1,cnt[cur^1]){
                    S=vis[cur^1][k],l=(S>>((j-1)<<1))&3,r=(S>>(j<<1))&3;
                    if(!mp[i][j]){if(!l&&!r)insert(S,dp[cur^1][k]);continue;}
                    if(!l&&!r){
                        if(!mp[i][j+1]||!mp[i+1][j])continue;
                        insert(S^(1<<((j-1)<<1))^(2<<(j<<1)),dp[cur^1][k]);
                    }if(l&&!r){
                        if(mp[i][j+1])insert(S^(l<<((j-1)<<1))^(l<<(j<<1)),dp[cur^1][k]);
                        if(mp[i+1][j])insert(S,dp[cur^1][k]);
                    }if(!l&&r){
                        if(mp[i+1][j])insert(S^(r<<(j<<1))^(r<<((j-1)<<1)),dp[cur^1][k]);
                        if(mp[i][j+1])insert(S,dp[cur^1][k]);
                    }if(l==1&&r==1){
                        dt=1;
                        fp(p,j+1,m){
                            val=(S>>(p<<1))&3;
                            if(val==1)++dt;if(val==2)--dt;
                            if(!dt){S^=(2<<(p<<1))^(1<<(p<<1));break;}
                        }insert(S^(1<<((j-1)<<1))^(1<<(j<<1)),dp[cur^1][k]);
                    }if(l==2&&r==2){
                        dt=1;
                        fd(p,j-2,0){
                            val=(S>>(p<<1))&3;
                            if(val==1)--dt;if(val==2)++dt;
                            if(!dt){S^=(1<<(p<<1))^(2<<(p<<1));break;}
                        }insert(S^(2<<((j-1)<<1))^(2<<(j<<1)),dp[cur^1][k]);
                    }if(l==2&&r==1)insert(S^(2<<((j-1)<<1))^(1<<(j<<1)),dp[cur^1][k]);
                    if(l==1&&r==2&&i==ex&&j==ey)ans+=dp[cur^1][k];
                }
            }
            fp(j,1,cnt[cur])vis[cur][j]<<=2;
        }
        printf("%lld\n",ans);
    }
}T;
int main(){return 0;}

原文地址:https://www.cnblogs.com/bztMinamoto/p/10066157.html

时间: 2024-10-13 01:18:59

P5056 【模板】插头dp的相关文章

【URAL 1519】【插头dp模板】Formula 1

1519. Formula 1 Time limit: 1.0 second Memory limit: 64 MB Background Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely

poj 1739 Tony&#39;s Tour 插头dp模板题

题意: 给一个迷宫,求左下角到右下角的路径数. 分析: 插头dp的模板题,建议先看cdq的论文再看代码,这份代码在模板基础上略微有改动.论文地址http://wenku.baidu.com/view/ed2b3e23482fb4daa58d4b74.html 代码: #include <iostream> using namespace std; const int maxD=16; const int HASH=10007; const int STATE=1000024; int N,M;

插头dp的几个模板

/* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring> #include<string> #include<iostream> #include<algorithm> #include<cmath> #include<map> #include<queue> #define LL lon

插头dp模板

(入门):https://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html (进阶)http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html 插头DP其实就是每格进行状态转移. 最小表示法太强了 保证数字≤状态长度,方便压成一个状态表示. 特点:数据小.非障碍格子连通. struct HASHMAP{ int head[HASH],next[STATE],state[STAT

插头dp

对于网格中的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> #

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

插头DP学习

队内没人会插头DP,感觉这个不会不行...所以我还是默默去学了一下, 学了一天,感觉会了一点.对于每一行,一共有j+1个插头,如果是多回路类的题目, 比较简单,可以用1表示有插头,0表示没有插头,这样就可以愉快转移了, 对于当前出来的位置(i,j),与它有关的插头有j-1和j 那么我们可以枚举状态经行转移. 对于单回路的问题....只是了解思想,目前还不会写,太笨了=_= poj 2411 Mondriaan's Dream 题意:用1*2小方块组成n*m矩阵有多少种组成方式 思路:我们从上到下

BZOJ 2595 游览计划(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2595 题意:给出一个数字矩阵.求一个连通块包含所有的数字0且连通块内所有数字之和最小. 思路:对于每个格子,是0则必须要选.那么对于不选的格子(i,j)在什么时候可以不选呢?必须同时满足以下两个条件: (1)(i,j)不是0: (2)(i-1,j)不选或者(i-1,j)选了但是轮廓线上还有别的地方与(i-1,j)是一个连通块. int Pre[105][N],op[105][N]; s

【插头dp】CDOJ1690 这是一道比CCCC简单题难的简单题

最裸的插头dp,可参见大白书. #include<cstdio> #include<cstring> using namespace std; #define MOD 1000000007 int f[2][(1<<5)+10],n,m; int main(){ scanf("%d%d",&n,&m); int cur=0; f[0][(1<<m)-1]=1; for(int i=0;i<n;++i){ for(in