zoukankan      html  css  js  c++  java
  • P5056-[模板]插头dp

    正题

    题目链接:https://www.luogu.com.cn/problem/P5056


    题目大意

    (n*m)的网格,求有多少条回路可以铺满整个棋盘。


    解题思路

    插头(dp)的,写法是按照题解上的写法。

    状态用的是括号匹配,然后用了哈希+邻接表(挂表)还有滚动数组优化空间

    然后可以看题解学


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int P=133331;
    struct node{
    	int to,next;
    }a[P*2];
    int n,m,o,tot,zx,zy,t[2],bit[25],ls[P],S[2][P],v[25][25];
    long long ans,dp[2][P];
    char st[25];
    void Add(int s,long long v){
    	int x=s%P;
    	for(int i=ls[x];i;i=a[i].next)
    		if(S[o][a[i].to]==s)
    		{dp[o][a[i].to]+=v;return;}
    	t[o]++;dp[o][t[o]]=v;S[o][t[o]]=s;
    	a[++tot].to=t[o];a[tot].next=ls[x];ls[x]=tot;
    	return;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%s",st+1);
    		for(int j=1;j<=m;j++)
    			if(st[j]=='.'){v[i][j]=1;zx=i;zy=j;}
    	}
    	for(int i=0;i<=12;i++)bit[i]=(1<<(i<<1));
    	t[o]=1;S[o][1]=0;dp[o][1]=1;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=t[o];j++)S[o][j]<<=2;//将右插头移到最左边 
    		for(int j=1;j<=m;j++){
    			o^=1;tot=t[o]=0;
    			memset(ls,0,sizeof(ls));
    			int s,dpl,rpl;long long w;
    			for(int k=1;k<=t[!o];k++){
    				s=S[!o][k];w=dp[!o][k];
    				dpl=(s>>(j<<1))%4;
    				rpl=(s>>(j-1<<1))%4;
    				if(!v[i][j]){//障碍 
    					if(!dpl && !rpl)Add(s,w);//不能有插头 
    				}
    				else if(!dpl && !rpl){//两边都没有插头
    					if(v[i+1][j]&&v[i][j+1])//开一个左上角插头 
    						Add(s+2*bit[j]+bit[j-1],w);
    				} 
    				else if(!dpl && rpl){//只有右插头 
    					if(v[i+1][j])Add(s,w);
    					if(v[i][j+1])Add(s-rpl*bit[j-1]+rpl*bit[j],w);
    				}
    				else if(dpl && !rpl){//只有下插头
    					if(v[i+1][j])Add(s-dpl*bit[j]+dpl*bit[j-1],w);
    					if(v[i][j+1])Add(s,w); 
    				}
    				else if(dpl==1&&rpl==1){
    					int c=1;
    					for(int p=j+1;p<=m;p++){
    						if((s>>(p<<1))%4==1)c++;
    						if((s>>(p<<1))%4==2)c--;
    						if(!c){Add(s-bit[j]-bit[j-1]-bit[p],w);break;}
    					}
    					
    				}
    				else if(dpl==2&&rpl==2){
    					int c=1;
    					for(int p=j-2;p>=0;p--){
    						if((s>>(p<<1))%4==2)c++;
    						if((s>>(p<<1))%4==1)c--;
    						if(!c){Add(s-2*bit[j]-2*bit[j-1]+bit[p],w);break;}
    					}
    				}
    				else if(dpl==1&&rpl==2)
    					Add(s-2*bit[j-1]-bit[j],w);
    				else if(dpl==2&&rpl==1)
    					if(i==zx&&j==zy)ans+=w;
    			}
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Web全栈探索,Vue基础系列,前后端交互(四)
    幸运者
    整数加法
    猜数游戏
    multi-select 左右选择插件
    Layui 踩坑记录
    jQuery 封装公共方法
    前后端文件内容 md5 计算
    Apscheduler 定时任务
    Git 开发流程
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14921055.html
Copyright © 2011-2022 走看看