状态压缩DP

例题https://www.luogu.com.cn/problem/P1896
状态压缩DP:
1.用二进制表示状态,用十进制数存储状态;
2.用位运算筛选出合法状态;
3.用位运算判断状态转移的条件;
4.计算时每个类累加上一行的兼容类。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int f[11][121][1 << 11];
// f[i][j][k]表示第i行放了j个国王的第k中状态的方案数
int s[500];
int num[1 << 11];
void solve()
{
	int n, k;
	cin >> n >> k;
	int cnt = 0;
	for (int i = 0; i < (1 << n); i++)
	{
		if (!(i & (i >> 1)))
		{
			s[cnt++] = i; // 预处理记录合法状态
			// 记录每个合法状态的国王数
			for (int j = 0; j < n; j++)
			{
				num[i] += (i >> j & 1);
			}
		}
	}
	// 不放国王也是一种方案
	f[0][0][0] = 1;
	/*
	第一层枚举层数
	第二层枚举国王数
	第三层枚举第i行的合法状态
	第四层枚举第i-1行的合法状态
	*/
	for (int i = 1; i <= n + 1; i++)
	{
		for (int j = 0; j <= k; j++)
		{
			for (int a = 0; a < cnt; a++)
			{
				for (int b = 0; b < cnt; b++)
				{
					int c = num[s[a]];
                    //转移方程 第一个个数必须合法 上一个合法的位置不跟当前行合法位置矛盾
					if (j >= c && !(s[a] & s[b]) && !(s[a] & (s[b] >> 1)) && !(s[a] & (s[b] << 1)))
					{
						f[i][j][a] += f[i - 1][j - c][b];
					}
				}
			}
		}
	}
	cout << f[n + 1][k][0] << endl;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}

例题2https://www.luogu.com.cn/problem/P1879
情况确实比上一题要少一点

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e8;
int mp[14];
int s[1 << 14];
int f[14][1 << 14];
void solve()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			int num;
			cin >> num;
			mp[i] = (mp[i] << 1) + num;
		}
	}
	int cnt = 0;
	for (int i = 0; i < (1 << m); i++)
	{
		if (!(i & (i >> 1)))
		{
			s[cnt++] = i;
		}
	}
	f[0][0] = 1;
	for (int i = 1; i <= n + 1; i++)
	{
		for (int a = 0; a < cnt; a++)
		{
			for (int b = 0; b < cnt; b++)
			{
				if ((s[a] & mp[i]) == s[a] && !(s[a] & s[b]))
				{
					// f[i][a] += f[i - 1][b];
					f[i][a] = (f[i][a] + f[i - 1][b]) % mod;
				}
			}
		}
	}
	cout << f[n + 1][0] << endl;
	// int ans = 0;
	// for (int i = 0; i <= cnt; i++)
	// {
	// 	ans += f[n][i];
	// }
	// cout << ans;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin>>t;
	while (t--)
	{
		solve();
	}
	return 0;
}

posted @ 2026-05-20 22:41  Ultramans  阅读(8)  评论(0)    收藏  举报