【AtCoder ABC310D】Peaceful Teams 题解(深度优先搜索+暴力枚举+剪枝)

[ABC310D] Peaceful Teams

题面翻译

N N N 位运动员,其中 A i A_i Ai B i B_i Bi 1 ≤ i ≤ M 1 \le i \le M 1iM)两人不能在同一小组,现在,我们给定小组数 T T T 请你分配他们到任意一个小组。注意小组不能为空。请求出所有不同的方案的数量。

题目描述

$ N $ 人のスポーツ選手がいます。

$ N $ 人の選手たちには互いに相性の悪い選手のペアが $ M $ 組あり、相性の悪い組のうち $ i\ (1\leq\ i\leq\ M) $ 組目は $ A\ _\ i $ 番目の選手と $ B\ _\ i $ 番目の選手です。

あなたは、選手を $ T $ チームに分けます。 どの選手もちょうど一つのチームに属さなければならず、どのチームにも少なくとも一人の選手が属さなければなりません。 さらに、どの $ i=1,2,\ldots,M $ についても、 $ A\ _\ i $ 番目の選手と $ B\ _\ i $ 番目の選手が同じチームに属していてはいけません。

この条件を満たすチーム分けの方法は何通りあるか求めてください。 ただし、チーム分けの方法が異なるとは、ある二人が存在して、彼らが一方のチーム分けでは同じチームに所属し、もう一方では異なるチームに所属することをいいます。

输入格式

入力は以下の形式で標準入力から与えられる。

$ N $ $ T $ $ M $ $ A\ _\ 1 $ $ B\ _\ 1 $ $ A\ _\ 2 $ $ B\ _\ 2 $ $ \vdots $ $ A\ _\ M $ $ B\ _\ M $

输出格式

答えを $ 1 $ 行で出力せよ。

样例 #1

样例输入 #1

5 2 2
1 3
3 4

样例输出 #1

4

样例 #2

样例输入 #2

5 1 2
1 3
3 4

样例输出 #2

0

样例 #3

样例输入 #3

6 4 0

样例输出 #3

65

样例 #4

样例输入 #4

10 6 8
5 9
1 4
3 8
1 6
4 10
5 7
5 6
3 7

样例输出 #4

8001

提示

制約

  • $ 1\leq\ T\leq\ N\leq10 $
  • $ 0\leq\ M\leq\dfrac{N(N-1)}2 $
  • $ 1\leq\ A\ _\ i\lt\ B\ _\ i\leq\ N\ (1\leq\ i\leq\ M) $
  • $ (A\ _\ i,B\ _\ i)\neq\ (A\ _\ j,B\ _\ j)\ (1\leq\ i\lt\ j\leq\ M) $
  • 入力はすべて整数

Sample Explanation 1

次の $ 4 $ 通りのチーム分けが条件を満たします。 ![](https://img.atcoder.jp/abc310/b92c2629f68d56350fe18e6d0a8fa060.png) 他に条件を満たすチーム分けは存在しないので、$ 4 $ を出力してください。

Sample Explanation 2

条件を満たすチーム分けがひとつも存在しないこともあります。

Sample Explanation 3

相性の悪いペアがひとつも存在しないこともあります。


思路

首先从输入中读取运动员的数量、组的数量和冲突的数量。然后,对于每个冲突,读取两个有冲突的运动员的编号,并在二维bitset数组cf中标记这个冲突。

接下来,执行深度优先搜索来枚举所有可能的分组方案。在每一步中,尝试将当前的运动员加入到一个已有的组中,或者创建一个新的组。在每种尝试中,检查是否会导致冲突。如果会导致冲突,跳过这种尝试。如果不会导致冲突,递归地对下一个运动员进行同样的处理。

在深度优先搜索的过程中,使用一个计数器tcnt记录当前已经创建的组的数量。当所有的运动员都被处理完毕后,如果已经创建的组的数量等于预期的组的数量,说明找到一个有效的分组方案,此时返回1,否则返回0。

最后,将所有返回的值累加起来,就得到所有可能的分组方案的数量。输出这个数量,就得到问题的答案。


AC代码

#include 
#include 
#include 
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;

const int N = 15;

// 人数、队伍数、冲突数
int n, t, m;
int tcnt;
bitset<N> cf[N];
unordered_set<int> team[N];

ll dfs(int d) {
	if (d == n + 1) {
		return (ll)(tcnt == t);
	}

	ll r = 0;
	// 加入已有队伍
	for (int i = 1; i <= tcnt; i++) {
		// 检测冲突
		bool flg = 0;
		for (const auto j : team[i]) {
			if (cf[d][j]) {
				flg = 1;
				break;
			}
		}
		if (flg) {
			continue;
		}

		team[i].insert(d);
		r += dfs(d + 1);
		team[i].erase(d);
	}

	// 创建新队伍
	team[++tcnt].insert(d);
	r += dfs(d + 1);
	team[tcnt--].erase(d);

	return r;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	tcnt = 0;

	cin >> n >> t >> m;
	for (int i = 1; i <= m; i++) {
		int a, b;
		cin >> a >> b;
		cf[a][b] = cf[b][a] = 1;
	}

	cout << dfs(1) << "\n";
	return 0;
}

你可能感兴趣的:(Algorithm,Problems,深度优先,剪枝,算法)