相互不可侵「状態圧縮DP」

トレーニングチームトレーニング⑨-バーチャルジャッジ

1.違法なステータスの判断に注意を払う

2.バイナリを使用して、最初にすべての状態を取得します

3.次に、それが合法であるかどうかを判断します。合法である場合は、転送に保存します。

#include <iostream>
#include <vector>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#define int long long
using namespace std;

const int N = 12, M = 1 << 10, K = 110;
int n,m;
vector<int> state;
int id[M],cnt[M];
vector<int> head[M];
int f[N][K][M];

//检查是否合法
//如果连着两个状态都是1,那必然不合法
bool check(int state)
{
	for (int i=0;i<n;i++)
		if((state >> i & 1) && (state >> (i + 1) & 1))
			return false;
	return true;
}
//统计1的个数
int count(int state)
{
	int res = 0;
	for(int i=0;i<n;i++) res += state >> i & 1;
	return res;
}

signed main() {
	cin>>n>>m;
	for(int i=0;i < 1 << n;i++)
	{
//		如果合法
		if(check(i)){
			state.push_back(i);
//			记录一下位置
			id[i] = state.size() - 1;
//			记录一下用了几个
			cnt[i] = count(i);
		}
	}
//	然后就开始连状态变化了
	for(int i=0;i<state.size();i ++)
		for(int j=0;j<state.size();j++)
		{
			int a = state[i];int b = state[j];
			if((a & b) == 0 && check(a | b)){
				head[i].push_back(j);
			}
		}
	f[0][0][0]=1;
	for(int i=1;i<=n+1;i++)
		for(int j=0;j<=m;j++)
			for(int a = 0;a < state.size();a++)
				for(int b : head[a]){
					int c = cnt[state[a]];
					if(j>=c){
						f[i][j][a] += f[i-1][j-c][b];
					}
				}
	cout<<f[n+1][m][0]<<endl;
}

おすすめ

転載: blog.csdn.net/weixin_60789461/article/details/123500437