链接 accode D
D - Peaceful Teams
记录一种新的枚举方式,就是简单战队,一共n个人需要排t个队,每队最少一人,记录所有的站队方法,这里我们不直接枚举每一队内有多少人,这多少人又是谁,太难实现,这里我们转换思路,反正排完队也要具体到每个人,不如直接枚举每个人的队号。
要注意的一点是我们所统计的站队情况是不含重复情况的 就是 [4][2,1][3]和[3][4][2,1]这属于同一站队情况,队号只是我们为了表示方便设计的。
还有一点是 直接枚举每个人的队号必然会出现上面重复的情况很难搞,所以我们还需要一点技巧,就是我们可以递增枚举队号,意思就是第一个人我们只要他在1号队伍,第二个人可以在[1,2]号队伍中,第三个人可以在[1,2,3]号队伍中,第四个人可以在[1,2,3,4]号队伍中,第n个人可以在[1,2,3…,n]号队伍中,这时候队伍数可能没有n个,那么我们只需要统计的时候减枝就好了,只统计人数到n队伍数到t的所以情况即可,接下来就是代码实现了(问题中还约束了M对人不能同时出现在一个队伍中,这个因为我们提前标记了每个同学的队号,所以到时候统计的时候再check一遍即可)
code
//最坏时间复杂度 N!*M
//但实际上通过减枝等操作实际复杂度要小得多
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
int T, N, M;
void solve()
{
int res = 0;
cin >> N >> T >> M;
vector<int> a(N+10);
vector<pii> c(M+10);
for(int i = 1; i <= M; i ++)
{
cin >> c[i].first >> c[i].second;
}
function<void(int, int)> dfs = [&](int x, int y){
if(x == N+1)//N位小朋友已经站好队了
{
if(y != T+1)//y == T+1说明这串dfs中有小朋友站到T队伍了,说明1-T都至少一人
{
return ;
}
bool ok = true;
for(int i = 1; i <= M; i ++)
{
if(a[c[i].first] == a[c[i].second])//检查站好队的小朋友中是否出现矛盾
{
ok = false;
}
}
res += ok;
return ;
}
for(int i = 1; i <= y; i ++)
{
a[x] = i;//给第x个小朋友分配队号i
dfs(x+1, max(y, i+1));//递增分配队伍确保不重复,可以自己画图思考思考 而且y是不减的
}
};
dfs(1, 1);//第1个小朋友,第一个队伍
cout << res << endl;
}
int main()
{
solve();
return 0;
}