zoukankan      html  css  js  c++  java
  • P5056 【模板】插头dp

    (color{#0066ff}{ 题目描述 })

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

    (color{#0066ff}{输入格式})

    第1行,n,m(2<=n,m<=12)

    从第2行到第n+1行,每行一段字符串(m个字符),"*"表不能铺线,"."表必须铺

    (color{#0066ff}{输出格式})

    输出一个整数,表示总方案数

    (color{#0066ff}{输入样例})

    4 4
    **..
    ....
    ....
    ....
    

    (color{#0066ff}{输出样例})

    2
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{ 题解 })

    插头DP本来以为多niubility的算法原来本质还是个DP,就是情况多了点qwq

    状压分割线,有三种情况,无,左插头,右插头(详见洛谷题解懒得写了

    只要明白状态分析出所有情况即可

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    std::unordered_map<LL, LL> f[2];
    //我TM就不写hash表
    int n, m, s, t;
    bool mp[100][100];
    char getch() {
    	char ch = getchar();
    	while(ch != '*' && ch != '.') ch = getchar();
    	return ch;
    }
    void init() {
    	n = in(), m = in();
    	for(int i = 1; i <= n; i++) 
    		for(int j = 1; j <= m; j++) {
    			mp[i][j] = getch() == '.';
    			if(mp[i][j]) s = i, t = j;
    		}
    }
    LL pos(int v, int x) { return (v << (x << 1)); }
    //返回第x大块的v状态(两个二进制来状压)
    LL work() {
    	int now = 0, nxt = 1;
    	f[0][0] = 1;
    	LL U = (1LL << ((m + 1) << 1)) - 1;
    	//全集
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m; j++) {
    			f[nxt].clear();
    			for(auto &k:f[now]) {
    				LL S = k.first, val = k.second;
    				LL L = (S >> ((j - 1) << 1)) & 3, R = (S >> (j << 1)) & 3;
    				//分割线(L是当前竖着的那个,R是紧接着横着的那个)
    				if(!mp[i][j]) {
    					if(!L && !R) f[nxt][S] += val;
    					continue;
    				}
    				// 0 0
    				if(!L && !R) {
    					if(mp[i][j + 1] && mp[i + 1][j]) f[nxt][S ^ pos(1, j - 1) ^ pos(2, j)] += val;
    					//0 0 -> 1 2
    				}
    				//2 1
    				else if(L == 2 && R == 1) {
    				//2 1 -> 0 0
    					f[nxt][S ^ pos(L, j - 1) ^ pos(R, j)] += val;
    				}
    				// 0 1 // 1 0 // 0 2 // 2 0 
    				else if(!L || !R) {
    					//0 1 // 0 2
    					if(!L) {
    						//拐弯
    						if(mp[i][j + 1]) f[nxt][S] += val;
    						//不拐弯
    						if(mp[i + 1][j]) f[nxt][S ^ pos(L, j - 1) ^ pos(L, j) ^ pos(R, j - 1) ^ pos(R, j)] += val;
    					}
    					//同上
    					else if(!R) {
    						if(mp[i][j + 1]) f[nxt][S ^ pos(L, j - 1) ^ pos(L, j) ^ pos(R, j - 1) ^ pos(R, j)] += val;
    						if(mp[i + 1][j]) f[nxt][S] += val;
    					}
    				}
    				//1 1 // 2 2
    				else if(L == R) {
    					// 1 1
    					if(L == 1) {
    						int du = 0;
    						//1 1 -> 0 0 但是源头接口处右插头变成左插头
    						for(int p = j; ; p++) {
    							LL o = (S >> (p << 1)) & 3;
    							if(o == 1) du++;
    							if(o == 2) du--;
    							if(!du) {
    								//原来状态消去,弄上新状态
    								f[nxt][S ^ pos(L, j - 1) ^ pos(R, j) ^ pos(2, p) ^ pos(1, p)] += val;
    								break;
    							}
    						}
    					}
    					//根上面差不多
    					else if(L == 2) {
    						int du = 0;
    						for(int p = j - 1; ; p--) {
    							LL o = (S >> (p << 1)) & 3;
    							if(o == 1) du--;
    							if(o == 2) du++;
    							if(!du) {
    								f[nxt][S ^ pos(L, j - 1) ^ pos(R, j) ^ pos(2, p) ^ pos(1, p)] += val;
    								break;
    							}
    						}
    					}
    				}
    				//本状态当且仅当是终点,用于封口
    				else if(L == 1 && R == 2 && i == s && j == t) return val;
    			}
    			std::swap(now, nxt);
    		}
    		f[nxt].clear();
    		//末尾的竖分割线到了下一行就变成了行首的分割线,把状态《《给分割线腾出地方
    		for(auto &k:f[now]) f[nxt][(k.first << 2) & U] += k.second;
    		std::swap(now, nxt);
    	}
    	return 0;
    }
    int main() {
    	init();
    	printf("%lld
    ", work());
    	return 0;
    }
    
  • 相关阅读:
    常量的定义
    二进制、八进制、十进制、十六进制间的转换
    使用简单的 5 个步骤设置 Web 服务器集群
    新手推荐:IIS+PHP+MYSQL环境配置教程
    windows7 iis安装与配置
    web服务器配置方法
    如何配置web服务器
    系统没有“internet信息服务(IIS)管理器”
    Html 内嵌 选择器属性 Dom操作 JavaScript 事件
    <转载>使用css让大图片不超过网页宽度
  • 原文地址:https://www.cnblogs.com/olinr/p/10235519.html
Copyright © 2011-2022 走看看