【ssl1383】车2(II)【状压DP】

62 篇文章 0 订阅
48 篇文章 0 订阅

在这里插入图片描述

Sample Input

3 3 2

Sample Output

24

分析

做状压DP的我心态逐渐爆炸。

首先我们要用DFS枚举每一行的状态。用 a [ j s ] a[js] a[js]表示状态的二进制数, n u m [ j s ] num[js] num[js]表示每行棋子的个数。

void dfs(int ans,int dep,int ff)
{
	if(dep>n)
	{
		js++;
		a[js]=ans;
		num[js]=ff;
		return;
	}
	dfs(ans,dep+1,ff);
	dfs(ans+(1<<(dep-1)),dep+2,ff+1);
}

然后进行DP。
f [ i ] [ a [ j ] ] [ l ] f[i][a[j]][l] f[i][a[j]][l]为第i行a[j]的状态下棋子为l所得的方案数。
可得动态转移方程:
f [ i ] [ a [ j ] ] [ l ] + = f [ i − 1 ] [ a [ w ] ] [ l − n u m [ j ] ] ; f[i][a[j]][l]+=f[i-1][a[w]][l-num[j]]; f[i][a[j]][l]+=f[i1][a[w]][lnum[j]];
DP之后累加所有方案数。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;

int n,m,k,js,ans;
int a[100001],num[100001],c[100001];
int f[82][1<<9][21];

void dfs(int ans,int dep,int ff)//dfs枚举每一行的状态
{
	if(dep>n)//当前行结束,统计
	{
		js++;
		a[js]=ans;
		num[js]=ff;
		return;
	}
	dfs(ans,dep+1,ff);//这个点不放
	dfs(ans+(1<<(dep-1)),dep+2,ff+1);//这个点放
}

int main()
{
    cin>>n>>m>>k;
    if(n<m) swap(n,m);
    dfs(0,1,0);
    for(int i=1;i<=js;i++)//初始化
    {
    	f[1][a[i]][num[i]]=1;
    }
    for(int i=2;i<=m;i++)
    {
    	for(int j=1;j<=js;j++)//枚举上一行状态
    	{
    		for(int w=1;w<=js;w++)//枚举当前行的状态
    		{
    			if(a[j]&a[w])//如果是(1,1)就不能转移,只有(0,0),(0,1),(1,0)可以
    			{
    				continue;
    			}
    			for(int l=0;l<=k;l++)
    			{
    				if(l>=num[j])//不能减出负数
    				{
    					f[i][a[j]][l]+=f[i-1][a[w]][l-num[j]];//根据上一个状态转移过来
    				}
    			}
    		}
    	}
    }
    for(int i=1;i<=js;i++)
    {
    	ans+=f[m][a[i]][k];//累加所有的方案
    }
    cout<<ans;
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值