freee Programming Contest 2023(AtCoder Beginner Contest 310)

文章介绍了一种新的枚举方法来解决N个人需要排成t个队伍的问题,其中每个队伍至少有一人。通过递增分配队号避免了重复情况,并在代码实现中考虑了M对人不能在同一队伍的约束,使用C++编写,实际复杂度远小于最坏时间复杂度N!*M。
摘要由CSDN通过智能技术生成

链接 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向夕阳Salute

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值