为防止广告,目前nocow只有登录用户能够创建新页面。如要创建页面请先登录/注册(新用户需要等待1个小时才能正常使用该功能)。

Sgu/131

来自NOCOW
< Sgu
跳转到: 导航, 搜索

状态压缩DP,转移的时候情况很多,要一个个写出来理清楚再写。 一行一行推,opt1为上一行的状态,opt2为当前行的状态, u1,u2分别为上下两行是否与左边相连而凸出来。

/*
     Case   1    2    3    4          5          6          7
            |    +-   |    L  or U    L| or U|   -+ or -+   L or U or L or U
            |    |    +-   --    --   -+    -+   W|    L|   W    W    L    L
 
     old    L     : connect with Left block
            U     : connect with Upper block
     new    - | + : describe the shape of forms
     empty  W     : NO put this block, wait for the forms of next row
*/
#include <stdio.h>
using namespace std;
#define LL long long
 
int n, m, i;
LL f[10][512];
 
void dfs(int j, int opt1, int opt2, int u1, int u2)
{
     if (j == m)
     {
        if (!u1 && !u2) f[i + 1][opt2] += f[i][opt1]; 
        return;
     }
     // Put this block
     if (!u2)
     {
        if (!u1)
        {
           dfs(j+1, opt1<<1, (opt2<<1)+1, 0, 0); // Case 1
           dfs(j+1, opt1<<1, (opt2<<1)+1, 1, 0); // Case 2
           dfs(j+1, opt1<<1, (opt2<<1)+1, 0, 1); // Case 3
        }
        dfs(j+1, (opt1<<1)+1-u1, (opt2<<1)+1, 0, 1); // Case 4
        dfs(j+1, (opt1<<1)+1-u1, (opt2<<1)+1, 1, 1); // Case 5
     }
     // NO put or Already put this block
     if (!u1) dfs(j+1, opt1<<1, (opt2<<1)+u2, 1, 1); // Case 6
     dfs(j+1, (opt1<<1)+1-u1, (opt2<<1)+u2, 0, 0); // Case 7
}
 
int main()
{
    scanf("%d %d", &n, &m);
    if (n < m) { n ^= m; m ^= n; n ^= m; }
    f[0][(1<<m)-1] = 1;
    for (i = 0; i < n; ++i)
        dfs(0, 0, 0, 0, 0);
    printf("%I64d", f[n][(1<<m)-1]);
    return 0;
}
// From FingerSed

6种放置方法分别枚举

/*
##     #.     ##    ##     #.   .#
..     #.     #.    .#     ##   ##
1      2      3      4      5    6
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long int LL;
const int maxn = 1<<11;
#define bin(i) (1<<i)
#define emp(a,i) (!(a&bin(i)))
int n,m,full;
LL g[maxn],f[maxn]; //f为当前行状态 g为枚举当前行状态后,对下一行的影响 
void dfs(int a,int b,LL k){
	if(a == full){ //要求铺满
		g[b] += k;
		return ;
	}
	for(int i=0;i<m;++i)if(emp(a,i)){
		if(i+1<m&&emp(a,i+1)){
			dfs(a|bin(i)|bin(i+1),b,k); //#1
			if(emp(b,i)) dfs(a|bin(i)|bin(i+1),b|bin(i),k);//#3
			if(i+1<m&&emp(b,i+1))dfs(a|bin(i)|bin(i+1),b|bin(i+1),k); //#4
		}
		if(emp(b,i)){
			dfs(a|bin(i),b|bin(i),k); //#2
			if(i+1<m&&emp(b,i+1))dfs(a|bin(i),b|bin(i)|bin(i+1),k); //#5
			if(i>=1&&emp(b,i-1))dfs(a|bin(i),b|bin(i)|bin(i-1),k); //#6
		}
		break; //每次进行一个状态的填充 
	}
}
int main()
{
	cin >> n >> m;
	full = (1<<m)-1; f[full] = 1;
	for(int k=0;k<=n;++k){//在首尾都加一行来避开统计,统一计数 
		for(int i=0;i<=full;++i)//枚举上一行状态
			if(f[i]) dfs(i,0,f[i]); //dfs枚举6个情况进行转移
		memcpy(f,g,sizeof(g));
		memset(g,0,sizeof(g));
	}
	cout <<f[0] <<endl;
	return 0;
}
个人工具