gym/100837 F - Controlled Tournament (树上 + 状压dp)

本文介绍了一种结合树形结构与状态压缩动态规划的方法,用于解决特定类型的比赛排序问题。该方法通过递归地探索所有可能的比赛顺序,并利用状态压缩技巧来减少计算复杂度,最终求得满足条件的比赛序列数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

已知 n 个人,知道 n 个人的实力,了解到两两比赛的结果,
现在让你安排 n 个人的比赛顺序。让编号 为 k 的人顺利。问你有几种安排的顺序。
安排的顺序要满足竞赛树的高度最小。

思路:

树上 + 状压 DP。

这里要考虑一下树的高度。
严格根据高度来 DP。

这里面有一个for循环,可以找到一个状态中 所有 1 的情况。

#include<bits/stdc++.h>
#define popcnt __builtin_popcount  //这个是查看 一个数中有多少个 1. 
using namespace std;
const int N = 20;
int a[N][N],f[N][N][1<<17];
int n,k;
int dfs(int u, int h, int s){
	if (popcnt(s) == 1) return 1;
	if (!h || ((1<<h) < popcnt(s))) return 0;
	int &ans = f[u][h][s];
	if (ans != -1) return ans;
	ans = 0;
	for (int t = s & (s-1); t; t = (t-1)&s)
		if (t & (1 << u)){
			for (int j = 0; j < n; ++j)
				if ((~t&(1<<j)) && (s &(1<<j)) && a[u][j]) ans += dfs(u,h-1,t)*dfs(j,h-1,s^t);
		}
	return ans;
}


int main(){	
	scanf("%d%d",&n,&k); 
	k--;
	for (int i = 0; i < n; ++i)
		for (int j =0; j < n; ++j)
			scanf("%d",&a[i][j]);
	int h = 0;	
	while( (1<<h) < n) h++;
	memset(f,-1,sizeof f);
	printf("%d\n",dfs(k,h,(1<<n)-1));
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值