【CF-GYM】【狀壓DP】100837F Controlled Tournament

CF-GYM 100837F Controlled Tournament

題目大意

NN個人參加比賽,其中你是比賽的組織者,你必須幫助第MM個人使他獲勝。求讓比賽輪數最小時的方案數。

分析

看到了這麼小的NN,我們很容易往狀壓 DP 上想。

考慮狀態f(i,S,d)f(i,S,d)表示當前參加的人爲SS,我們想讓第ii個人勝出且經過dd層的方案數。

轉移就枚舉SS的非空子集轉移即可。

但這樣用循環直接做的話複雜度爲O(3N×N3)O(3^N\times N^3)的。

我們發現這樣定義無用狀態其實非常多的,所以我們就用記憶化搜索來實現這個 DP 以規避無用狀態。

參考代碼

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int Maxn = 16;

inline int lowbit(int x) {return x & (-x);}
inline int bitcount(int x) {
	int ret = 0;
	while(x) ret++, x -= lowbit(x);
	return ret;
}
inline int height(int x) {
	int ret = 0;
	while((1 << ret) < x) ret++;
	return ret;
}

int N, M;
int R[Maxn + 5][Maxn + 5];
int h[Maxn + 5];

int f[7][Maxn + 3][(1 << Maxn) + 3];
int DFS(int dep, int win, int s) {
	if(f[dep][win][s] != -1) return f[dep][win][s];
	if(bitcount(s) == 1) {
		if(s & (1 << (win - 1))) return f[dep][win][s] = 1;
		else return f[dep][win][s] = 0;
	}
	f[dep][win][s] = 0;
	for(int t = (s - 1) & s; t > 0; t = (t - 1) & s) {
		int s1 = t, s2 = s ^ t;
		if(!(s1 & (1 << (win - 1)))) continue;
		if(h[bitcount(s1)] > dep - 1 || h[bitcount(s2)] > dep - 1)
			continue;
		int ans1 = DFS(dep - 1, win, s1);
		int ans2 = 0;
		for(int i = 1; i <= N; i++)
			if((s2 & (1 << (i - 1))) && R[win][i])
				ans2 += DFS(dep - 1, i, s2);
		f[dep][win][s] += ans1 * ans2;
	}
	return f[dep][win][s];
}

int main() {
//#ifdef LOACL
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
//#endif
	freopen("f.in", "r", stdin);
	freopen("f.out", "w", stdout);
	scanf("%d %d", &N, &M);
	for(int i = 1; i <= N; i++)
		for(int j = 1; j <= N; j++)
			scanf("%d", &R[i][j]);
	for(int i = 1; i <= N; i++)
		h[i] = height(i);
	memset(f, -1, sizeof f);
	printf("%d\n", DFS(h[N], M, (1 << N) - 1));
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章