【SSL_1383】车II

车II

Time Limit:1000MS Memory Limit:65536K
Total Submit:103 Accepted:62

Description

有一个nm的棋盘(n、m≤80,nm≤80)要在棋盘上放k(k≤20)个棋子,使得任意两个棋子不相邻。求合法的方案总数。

Input

n,m,k

Output

方案总数

Sample Input

3 3 2

Sample Output

24

思路

的拓展,
先dfs预处理出一行的全部合法(左右不相邻)状态且存储在s数组中。
f i , j , k f_{i,j,k} fi,j,k表示第i行的状态为 s j s_j sj且前i行总共放置k个棋子,
得: f 0 , 1 , 0 = 1 f_{0,1,0}=1 f0,1,0=1
f i , j , k = ∑ f i − 1 , l , k − c [ j ] f_{i,j,k}=\sum{f_{i-1,l,k-c[j]}} fi,j,k=fi1,l,kc[j]
枚举行数i,状态j,当前总旗子k,上一行状态l,四重循环。
其中c[j]表示状态 s j s_j sj中1的个数。且 s j & s l = = 0 s_j\&s_l==0 sj&sl==0,意思是 s j s_j sj s l s_l sl没有同为1的位,及满足上下不相邻。
最后发现f的第一维度行数i每次只会用到上一行,所以可以滚动,减少空间。

#include<iostream>
#include<cstring>
using namespace std;
int f[2][145][21];//滚动 DP数组
int n,m,kn,sn,s[145],c[145],ans;
void dfs(int dep,int ss,int sc)
{
	if(dep>m)
	{
		s[++sn]=ss;
		c[sn]=sc;
	}
	else
	{
		dfs(dep+1,ss,sc);
		dfs(dep+2,ss+(1<<dep-1),sc+1);
	}
}
int main()
{
	cin>>n>>m>>kn;
	if(m>n) swap(n,m);
	dfs(1,0,0);
	f[0][1][0]=1;
	for(int i=1; i<=n; i++)//枚举行
	{
		for(int j=1; j<=sn; j++)//枚举当前状态
		{
			for(int k=c[j]; k<=kn; k++)//枚举前i行棋子个数
			{
				for(int l=1; l<=sn; l++)//枚举上一行状态
				{
					if(!(s[j]&s[l])&&k-c[j]>=c[l]) f[i&1][j][k]+=f[!(i&1)][l][k-c[j]];
				}
			}
		}
		memset(f[!(i&1)],0,sizeof(f[!(i&1)]));//清空用过的滚动数组
	}
	for(int j=1;j<=sn;j++) ans+=f[n&1][j][kn];
	cout<<ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值