列表

详情


NC219897. 涛酱和策策的游戏again(by良心出题人wzc)

描述

涛酱和策策在训练之余会玩一些小游戏来放松头脑,今天他们又在玩小游戏,wzc在边上围观并记录了他们的游戏。
涛酱为策策准备了一个n*m的棋盘,他限制了其中某些格子是不可放置的。
策策的任务是用1*2的长方形填满这个棋盘除了不可放置的格子外的所有格子。(长方形水平或竖直放置均可,但相互之间不可重叠,且不能放在不可放置的格子上)

现在策策想知道他有多少种可行的摆放方案。

输入描述

输入包含多组测试数据。(每个测试点最多10组)
每组数据的第一行包含三个整数n,m,k,分别代表棋盘的长宽,以及棋盘上多少个格子被限制了不可放置。(1<=n,m<=11,0<=k<=n*m)
接下来k行,每行两个整数a,b。代表第a行第b列的格子被限制了不可放置。(1<=a<=n,1<=b<=m)
当输入的n=0,m=0,k=0表示输入终止,且该组数据无需处理。

输出描述

每组测试数据输出一个整数代表可行的摆放方案数量,每组样例输出占一行。

示例1

输入:

3 3 1
2 2
1 2 0
1 3 0
4 11 0
10 11 0
5 5 3
1 3
2 1
3 2
5 5 3
1 3
2 3
3 1
0 0 0

输出:

2
1
0
51205
3852472573499
0
80

说明:


原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 10ms, 内存消耗: 1184K, 提交时间: 2021-04-10 11:17:44

#include<iostream>
#include<cstring>
using namespace std;

const int N=13,M=1<<N;
long long dp[N][M];
int num[N];
int n,m,k;

int main()
{
	while(scanf("%d %d %d",&n,&m,&k)&&(n+m+k))
	{
		memset(dp,0,sizeof dp);
		memset(num,0,sizeof num);
		for(int i=0;i<k;i++)
		{
			int a,b;
			cin>>a>>b;
//			a--,b--;
			num[a]+=(1<<(b-1));
		}
		dp[1][num[1]]=1;
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<(1<<m);j++)
			{
				if(i!=1){
					int now=0;
					for(int ii=0;ii<m;ii++)
						if(!(j&(1<<ii))) now+=(1<<ii);
					if((now&num[i])==0) dp[i][now+num[i]]=dp[i-1][j];
				}
			}
			for(int ii=1;ii<m;ii++)
				for(int j=0;j<(1<<m);j++)
					if((j&(1<<ii))==0 && (j&(1<<(ii-1)))==0)
						dp[i][j+(1<<ii)+(1<<(ii-1))]+=dp[i][j];
		}
		cout<<dp[n][(1<<m)-1]<<endl;
	}
	return 0;
}

上一题