zoukankan      html  css  js  c++  java
  • UVA11270 Tiling Dominoes

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

    给定一个m×n的矩形网格,用1×2多米诺骨牌完全平铺。 请注意,即使一个平铺的旋转与另一个平铺相匹配,它们仍算作不同的平铺。 下面显示了一个平铺示例。 输入格式

    输入包括多组数据。每组数据占一行,包含两个整数m,n(n×m≤100)。输入结束标志为文件结束符(EOF)。 输出格式

    对于每组数据输出一行,输出总数。

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

    每组数据,两个整数 (n,m)

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

    对于每组数据,输出答案。

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

    2 10
    4 10
    8 8
    

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

    89
    18061
    12988816
    

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

    (n*mleq 100)

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

    一个状压DP,也可以写插头DP蒟蒻目前还不会

    可以发现,行或列其中一个一定不超过10,所以将其状压

    横着的块均为0, 竖着的块,上面为1, 下面为0

    因此,如果上一行的某位置为1,那么本行该位置必须为0, 代表竖着块的下半部分

    最后一行的状态必须为0

    如何判断一个状态能否作为某状态的下一行

    首先,对于横着的块,肯定是成对出现的,但是如果上一行是1,那么对应本行的0是属于竖着的块的,是独立的,不能与旁边的0拼成横着的

    可以发现,将它们进行按位或,那么那些特殊的0就成了1, 这时候判断一下每次连续的0是否有偶数个就行了

    对于上面是1下面必须是0的问题,可以按位与一下,为0就行了

    为了保证时间复杂度,与处理出合法拼接状态,就能过了

    #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;
    }
    using std::vector;
    LL f[120][2050];
    vector<int> v[2050][11];
    int n, m;
    bool cant(int zt, int lim) {
    	int tot = 0;
    	for(int i = 0; i < lim; i++) {
    		if(zt & (1 << i)) { 
    			if(tot & 1) return true;
    			tot = 0;
    		}
    		else tot++;
    	}
    	if(tot & 1) return true;
    	return false;
    }
    LL dfs(int dep, int zt) {
    	if(dep == n) return !zt;
    	if(f[dep][zt]) return f[dep][zt];
    	for(int i = 0; i < (int)v[zt][m].size(); i++) {
    		f[dep][zt] += dfs(dep + 1, v[zt][m][i]);
    	}
    	return f[dep][zt];
    }
    bool ok(int zt) {
    	for(int i = 1; i < 9; i++) 
    		if(!(zt & (1 << i)) && (zt & (1 << (i - 1))) && (zt & (1 << (i + 1)))) return false;
    	return true;
    }
    int main() {
    	for(int lim = 1; lim <= 10; lim++)
    		for(int i = 0; i < (1 << lim); i++)
    			for(int j = 0; j < (1 << lim); j++) {
    				if((i & j) || cant(i | j, lim)) continue;
    				v[i][lim].push_back(j);
    			}
    	while(~scanf("%d%d", &n, &m)) {
    		if(m > n) std::swap(n, m);
    		memset(f, 0, sizeof f);
    		if((n * m) & 1) puts("0");
    		else printf("%lld
    ", m == 1? (n & 1? 0 : 1) : dfs(0, 0));
    	}
    	return 0;
    }
    
  • 相关阅读:
    【JS】 Javascript 入门
    【CSS】 CSS的一些应用实例和参考
    【CSS】 CSS 定位
    【泛泛】 不知道怎么分类的豆知识
    【CSS】 CSS基础知识 属性和选择
    【HTML】 HTML基础知识 表单
    【HTML】 HTML基础知识 一些标签
    【Linux】 文本比较工具 diff和cmp
    php -- or 的用法
    php -- 检查是否存在
  • 原文地址:https://www.cnblogs.com/olinr/p/10228899.html
Copyright © 2011-2022 走看看