P8756 [蓝桥杯 2021 省 AB2] 国际象棋 状压dp统计情况数的一些小理解

建议有状压基础再食用:

n行m列 等价 n列m行 ,因为n比较小,int是32位足够了,我们用比特位统计每一行的状态。

本题的状态转移方程是

dp[h][i][j][num] = (dp[h][i][j][num] + dp[h - 1][j][ii][num - nums[i]])%mod;
h是行数,i和j表示本行状态和上一行状态,num表示个数。
nums[i]是情况为 i 时的bit位为1的数目,提前可以统计一下。
dp的值就是求的情况数。

很难理解,其实我们先不看i 和 j,只看行数和num,这才是dp的样子。
然后加上i和j状态压缩,就是状压dp了。

(动态规划是有条理的遍历,是全面覆盖的,num所有可以的情况都会遍历。本行i是0也会,所以只有前几行放棋子的,后面全是0也会遍历到的。)

dp代码片:

前一行和本行情况的比特位存在隔2的

前两行和本行情况的比特位存在隔1的情况直接略去,也就是马会互吃的情况。

//初始化
dp[0][0][0][0] = 1;//0行什么也不放。第一行肯定会摸一下,方案数是1
//

for (int h = 1; h <= m; h++)
{
	for (int i = 0; i < (1ll << n); i++)//本行
	{
		for (int j = 0; j < (1ll << n); j++)//前一行
		{
			for (int ii = 0; ii < (1ll << n); ii++)//前两行
			{
				for (int num = nums[i]; num <= k; num++)
				{
					if ((i << 2 & j) || (i >> 2 & j))
						continue;
					if ((i << 1 & ii) || (i >> 1 & ii))
						continue;

					dp[h][i][j][num] = (dp[h][i][j][num] + dp[h - 1][j][ii][num - nums[i]])%mod;

				}
			}
		}
	}
}

参考代码

int n,m,k;

int countb(int aim)
{
	int ret = 0;
	for (int i = 0; i < n; i++)
	{
		if (aim & (1ll << i))
		{
			ret++;
		}
	}
	return ret;
}

void solve()
{
	cin >> n >> m >> k;
	//n行m列  等价  n列m行
	//n列可统计状压
	vector<int>nums(1 << n);
	for (int i = 0; i < (1ll << n); i++)
	{
		nums[i] = countb(i);
	}
	vector<vector<vector<vector<int>>>>dp(m+1, vector<vector<vector<int>>>(		1ll<<n, vector<vector<int>>(1ll << n,vector<int>(k+1)	)  )	 );
	//第几行 本行状态 前一行状态 个数 == 方案数

	//
	dp[0][0][0][0] = 1;//0行什么也不放。第一行肯定会摸一下,方案数是1
	//

	for (int h = 1; h <= m; h++)
	{
		for (int i = 0; i < (1ll << n); i++)//本行
		{
			for (int j = 0; j < (1ll << n); j++)//前一行
			{
				for (int ii = 0; ii < (1ll << n); ii++)//前两行
				{
					for (int num = nums[i]; num <= k; num++)
					{
						if ((i << 2 & j) || (i >> 2 & j))
							continue;
						if ((i << 1 & ii) || (i >> 1 & ii))
							continue;

						dp[h][i][j][num] = (dp[h][i][j][num] + dp[h - 1][j][ii][num - nums[i]])%mod;

					}
				}
			}
		}
	}

	//后面都是0也包括了只在前几行放的。。
	//动归
	int ans = 0;
	for (int i = 0; i < (1ll << n); i++)//本行
	{
		for (int j = 0; j < (1ll << n); j++)//前一行
		{
			ans = (ans + dp[m][i][j][k]) % mod;
		}
	}
	cout << ans;
	return;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	//cin >> t;
	for (int i = 1; i <= t; i++)
	{
		solve();
	}
	return 0;
}

相关推荐

  1. P8753 [ 2021 AB2] 平方 Python

    2024-02-09 14:22:02       45 阅读
  2. 2021 AB 2 洛谷P8755 负载均衡

    2024-02-09 14:22:02       35 阅读
  3. P8706 [ 2020 AB1] 解码 Python

    2024-02-09 14:22:02       38 阅读
  4. P8752 [ 2021 B2] 特殊年份 Python

    2024-02-09 14:22:02       39 阅读
  5. [ 2023 A] 更(dp基础应用)

    2024-02-09 14:22:02       31 阅读
  6. [ 2021 AB2] 完全平方

    2024-02-09 14:22:02       36 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-09 14:22:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-09 14:22:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-02-09 14:22:02       82 阅读
  4. Python语言-面向对象

    2024-02-09 14:22:02       91 阅读

热门阅读

  1. C++ .h文件类的调用

    2024-02-09 14:22:02       51 阅读
  2. 机器学习原理到Python代码实现之PolynomialRegression

    2024-02-09 14:22:02       42 阅读
  3. List 差集

    2024-02-09 14:22:02       39 阅读
  4. 侵入式智能指针和非侵入式智能指针

    2024-02-09 14:22:02       44 阅读
  5. 动态规划C语言

    2024-02-09 14:22:02       39 阅读
  6. Jetpack Room使用

    2024-02-09 14:22:02       47 阅读
  7. 开源软件:引领技术创新与商业模式转型

    2024-02-09 14:22:02       50 阅读
  8. 2024年GPT如何发展?

    2024-02-09 14:22:02       50 阅读
  9. 开源软件的未来发展趋势与应对新挑战和机遇

    2024-02-09 14:22:02       59 阅读
  10. 问题 | 开源软件的影响力

    2024-02-09 14:22:02       42 阅读