• 插头 dp


    插头dp

    洛谷 黑题板子?
    P5056
    给出n×m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?

    1、轮廓线
    简单地说,轮廓线就是已决策格子和未决策格子的分界线;

    2,插头dp以每一个格子进行一次转移;

    3,一般设 dp[i][j][state]为(i,j)位置,状态为state的方案数(或者代价,等等让你求的东西……)
    所以我们状压什么呢?轮廓线。
    DP求解棋盘问题是逐格转移的。所以已经转移过的格子和没转移过的格子被一个折线分成了两半儿。这个折线就是轮廓线。

    注意轮廓线状态来确定用几进制数表示,例如这道题有三种状态可以用三进制表示,但是太麻烦 蒟蒻不会
    可以用四进制,因为我们一般用的都是二进制的运算,我们可以用两个二进制数表示一个四进制数;
    可以用哈希表存储状态,

    4,一般的,对于dp数组,我们可以滚动

    一些细节代码里看,由于我还没写,先用学长的;

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    #define int ll
    #define maxn 100010
    #define mod 1926223
    using namespace std;
    inline int read()
    { 
    	int x = 0 , f = 1 ; char ch = getchar() ; 
    	while(!isdigit(ch)) { if(ch == '-') f = -1 ; ch = getchar() ; }
    	while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0' , ch = getchar() ; 
    	return x * f ;
    }
    int n , m , hash[mod + 1] , dp[2][mod + 1] , vis[2][mod + 1] , cnt[2] ;
    int now , mp[22][22] , endx , endy , ans ;
    char opt[22] ;  
    inline void insert(int x , int k)
    {
    	int tmp = x % mod ; 
    	while(hash[tmp])
    	{
    		if(vis[now][hash[tmp]] == x) {
    			dp[now][hash[tmp]] += k ; return ;
    		}
    		tmp = (tmp + 1) % mod ;
    //		cout << "!" << endl ;
    	}
    	hash[tmp] = ++cnt[now] ; vis[now][cnt[now]] = x ; dp[now][cnt[now]] = k ;
    }
    inline void work()
    {
    	dp[0][1] = 1 ; cnt[0] = 1 ; vis[0][1] = 0 ;
    	for(int i = 1 ; i <= n ; ++i)
    	{
    		for(int j = 1 ; j <= m ; ++j)
    		{
    			cnt[now ^= 1] = 0 ; 
    			memset(hash , 0 , sizeof hash) ;
    			for(int k = 1 ; k <= cnt[now ^ 1] ; ++k)
    			{
    				int S = vis[now ^ 1][k] , L = (S >> ((j - 1) * 2)) & 3 , R = (S >> (j << 1)) & 3 ;//注意这个就是取出捆绑的两个二进制数;
    				int val = dp[now ^ 1][k] ;
    				if(!mp[i][j]) {
    //					if(!L && !R)
    					 insert(S , val) ;
    					continue ;
    				}
    				if(!L && !R)
    				{
    					if(mp[i+1][j] && mp[i][j+1]) insert(S ^ (1 << ((j - 1) << 1)) ^ (2 << (j << 1)) , val) ;
    				}
    				if(!L && R)
    				{
    					if(mp[i][j+1]) insert(S , val) ; 
    					if(mp[i+1][j]) insert(S ^ (R << (j << 1)) ^ (R << ((j - 1) << 1)) , val) ;
    				}
    				if(L && !R)
    				{
    					if(mp[i+1][j]) insert(S , val) ; 
    					if(mp[i][j+1]) insert(S ^ (L << ((j - 1) << 1)) ^ (L << (j << 1)) , val) ;
    				}
    				if(L == 1 && R == 1)
    				{
    					int du = 0 ; 
    					for(int p = j + 1 ; ; ++p)
    					{
    						int state = (S >> ((p - 1) << 1)) & 3 ; 
    						if(state == 1) du ++ ; 
    						if(state == 2) du -- ; 
    						if(du == 0) {
    							int dou = S ^ (1 << ((j - 1) << 1)) ^ (1 << (j << 1)) ;  
    							insert(dou ^ (2 << ((p - 1) << 1)) ^ (1 << ((p - 1) << 1)) , val) ; 
    							break ;
    						}
    					}
    				}
    				if(L == 2 && R == 2)
    				{#nvluf ec j  
    					int du = 0 ; 
    					for(int p = j ; ; --p)
    					{
    						int state = (S >> ((p - 1) << 1)) & 3 ; 
    						if(state == 1) du ++ ; 
    						if(state == 2) du -- ; 
    						if(du == 0) {
    							int dou = S ^ (2 << ((j - 1) << 1)) ^ (2 << (j << 1)) ;  
    							insert(dou ^ (1 << ((p - 1) << 1)) ^ (2 << ((p - 1) << 1)) , val) ; 
    							break ;
    						}
    					}
    				}
    				if(L == 2 && R == 1)
    					insert(S ^ (2 << ((j - 1) << 1)) ^ (1 << (j << 1)) , val);
    				if(L == 1 && R == 2 && i == endx && j == endy)
    					ans += val ;
    			}
    		}
    		for(int j = 1 ; j <= cnt[now] ; ++j) vis[now][j] <<= 2 ;
    	}
    	printf("%lld
    " , ans) ;
    }
    signed main()
    {
    	n = read() , m = read() ; 
    	for(int i = 1 ; i <= n ; ++i) { 
    		scanf("%s" , opt + 1) ; 
    		for(int j = 1 ; j <= m ; ++j)
    			if(opt[j] == '.')
    				mp[i][j] = 1 , endx = i , endy = j ;
    	}
    	work() ; 
    }
    
  • 相关阅读:
    1026. 程序运行时间(15)
    C语言字符串/数组去重
    1025. 反转链表 (25)
    1024. 科学计数法 (20)
    1023. 组个最小数 (20)
    1022. D进制的A+B (20)
    1021. 个位数统计 (15)
    1020. 月饼 (25)
    前端001/正则表达式
    SSM001/构建maven多模块项目
  • 原文地址:https://www.cnblogs.com/Aswert/p/13616358.html
Copyright © 2020-2023  润新知