• 【bzoj3125】CITY 插头dp


    题目描述

    给出一个n*m的矩阵,某些格子不能通过,某些格子只能上下通过或左右通过。求经过所有非不能通过格子的哈密顿回路条数。

    输入

    第一行有两个数N, M表示地图被分割成N*M个块,接下来有N行,每行有M个字符。
     .  表示这个块可以通过
     - 表示这个块只可以左右通过
     | 表示这个块只可以上下通过
     # 表示这个块不能通过
    (从每个块只能走到其上下左右相邻的四个块)

    输出

    一个数,表示小明把所以可以通过的块都经过且只经过一次并回到原地的方案数。

    样例输入

    4 4
    ....
    ..-.
    ....
    ....

    样例输出

    1


    题解

    插头dp

    这道题 的唯一差别在于:部分格子只能上下通过或只能左右通过。

    因此判断条件那里改一改就好了。

    这里学了一下 CQzhangyu 的技♂巧:判断时只需要判断当前状态是否适用于当前格子,以及转移是否适用于当前格子即可。这样不合法的状态就会在下一步剪掉。这一步可以省很大的代码量。

    注意开long long(题面的long指的就是int)

    #include <cstdio>
    #include <cstring>
    typedef long long ll;
    int m , a[13][13] , b[13] , w[1600000] , v[42000] , tot;
    ll f[13][13][42000];
    char str[14];
    void dfs(int p , int c , int now)
    {
    	if(c < 0 || c > m - p + 1) return;
    	if(p > m)
    	{
    		w[now] = ++tot , v[tot] = now;
    		return;
    	}
    	dfs(p + 1 , c , now);
    	dfs(p + 1 , c + 1 , now + b[p]);
    	dfs(p + 1 , c - 1 , now + 2 * b[p]);
    }
    inline int l(int v , int p)
    {
    	int i , c = 0;
    	for(i = p ; ~i ; i -- )
    	{
    		if(v / b[i] % 3 == 1) c -- ;
    		if(v / b[i] % 3 == 2) c ++ ;
    		if(!c) return i;
    	}
    	return -1;
    }
    inline int r(int v , int p)
    {
    	int i , c = 0;
    	for(i = p ; i <= m ; i ++ )
    	{
    		if(v / b[i] % 3 == 1) c ++ ;
    		if(v / b[i] % 3 == 2) c -- ;
    		if(!c) return i;
    	}
    	return -1;
    }
    int main()
    {
    	int n , i , j , k , x , y , p , q;
    	ll ans = 0;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%s" , str + 1);
    		for(j = 1 ; j <= m ; j ++ )
    		{
    			if(str[j] == '.' || str[j] == '-') a[i][j] |= 1;
    			if(str[j] == '.' || str[j] == '|') a[i][j] |= 2;
    			if(str[j] != '#') x = i , y = j;
    		}
    	}
    	b[0] = 1;
    	for(i = 1 ; i <= m ; i ++ ) b[i] = b[i - 1] * 3;
    	dfs(0 , 0 , 0);
    	f[0][m][w[0]] = 1;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		for(j = 1 ; j <= tot ; j ++ )
    			if(v[j] % 3 == 0)
    				f[i][0][j] = f[i - 1][m][w[v[j] / 3]];
    		for(j = 1 ; j <= m ; j ++ )
    		{
    			for(k = 1 ; k <= tot ; k ++ )
    			{
    				p = v[k] / b[j - 1] % 3 , q = v[k] / b[j] % 3;
    				if((p && !(a[i][j] & 1)) || (q && !(a[i][j] & 2))) continue;
    				if(!a[i][j]) f[i][j][k] += f[i][j - 1][k];
    				else
    				{
    					if(!p && !q && a[i][j] == 3) f[i][j][w[v[k] + b[j - 1] + 2 * b[j]]] += f[i][j - 1][k];
    					if(!p && q && a[i][j] & 1) f[i][j][k] += f[i][j - 1][k];
    					if(p && !q && a[i][j] & 2) f[i][j][k] += f[i][j - 1][k];
    					if(!p && q) f[i][j][w[v[k] + q * (b[j - 1] - b[j])]] += f[i][j - 1][k];
    					if(p && !q) f[i][j][w[v[k] + p * (b[j] - b[j - 1])]] += f[i][j - 1][k];
    					if(p == 1 && q == 1) f[i][j][w[v[k] - b[j - 1] - b[j] - b[r(v[k] , j)]]] += f[i][j - 1][k];
    					if(p == 2 && q == 2) f[i][j][w[v[k] - 2 * (b[j - 1] + b[j]) + b[l(v[k] , j - 1)]]] += f[i][j - 1][k];
    					if(p == 2 && q == 1) f[i][j][w[v[k] - 2 * b[j - 1] - b[j]]] += f[i][j - 1][k];
    					if(p == 1 && q == 2 && i == x && j == y && v[k] == b[j - 1] + 2 * b[j]) ans += f[i][j - 1][k];
    				}
    			}
    		}
    	}
    	printf("%lld
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    SaaS多租户模式数据存储方案比较
    **Apache的Order Allow,Deny 详解
    php使用gd库将文字转换成图片(转)
    [git] warning: LF will be replaced by CRLF | fatal: CRLF would be replaced by LF[ git 处理和修改行结束符(CRLF和LF)]
    解决Linux CentOS中cp -f 复制强制覆盖的命令无效的方法
    【个人专用&入门级】LAMP一键安装包
    【转】负载均衡软件选型
    Apache不重新编译,利用apxs工具给Apache添加模块,如cgi模块
    [Apache手册]Linux环境下配置Apache运行cgi
    phpMyAdmin提示:配置文件权限错误,无法写入!解决方法
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8134237.html
Copyright © 2020-2023  润新知