CCPC-Wannafly Winter Camp Day2 (Div2, onsite) K Sticks 暴力 折半枚举

本文介绍了一种解决12根木棒分组问题的优化算法,通过深度优先搜索(DFS)和状态枚举降低复杂度,实现高效求解。文章详细解析了代码实现过程,包括状态枚举、三角形条件检查等关键步骤。

题解

一共12根木棒如果直接DFS每3根分一组复杂度非常高再乘上6000组样例直接爆炸 先使用DFS枚举状态 每次只枚举一半
12根里面选6根另外6根自然也确定了 再从6根里面选3根同理剩下三根自然也会确定 这样复杂度就会将C(12, 6)*C(6, 3)*常数
枚举出来的状态前一半处理过程中状态取反已经将后面的包含了 所以只需要用前一半即可

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e4;
int a[MAXN], p[MAXN], q[MAXN], x[MAXN], y[MAXN];

void DFS(int d, int n, int l, int t, int s, int *arr, int &cnt) //深度 总数 上取 总取 状态 存储 数量
{
	if (t == n / 2)
	{
		arr[cnt++] = s;
		return;
	}
	if (d == n)
		return;
	for (int i = l; i < n; i++)
		DFS(d + 1, n, i + 1, t + 1, s | (1 << i), arr, cnt);
}
void take(int *arr, int *res, int n, int s) //按照s将状态取出
{
	int pos = 0;
	for (int i = 0; i < n; i++)
		if (s & (1 << i))
			res[pos++] = arr[i];
}
bool check(int a, int b, int c)
{
	if (a + b > c && a + c > b && b + c > a)
		return true;
	return false;
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int pl = 0, ql = 0;
	DFS(0, 12, 0, 0, 0, p, pl); //12取6状态存入p
	DFS(0, 6, 0, 0, 0, q, ql); //6取3状态存入q
	pl /= 2, ql /= 2; //枚举前一半状态后一半已经覆盖
	int T;
	cin >> T;
	for (int ti = 1; ti <= T; ti++)
	{
		for (int i = 0; i < 12; i++)
			scanf("%d", &a[i]);
		vector<int> ans, vec1, vec2, vec3; //可以优化不用vector不想改了~
		for (int i = 0; i < pl; i++) //枚举12选6状态
		{
			vec1.clear(), vec2.clear();
			take(a, x, 12, p[i]);
			for (int j = 0; j < ql; j++) //枚举6选3状态
			{
				vec3.clear();
				take(x, y, 6, q[j]);
				if (check(y[0], y[1], y[2]))
					vec3.push_back(y[0]), vec3.push_back(y[1]), vec3.push_back(y[2]);
				take(x, y, 6, ~q[j]);
				if (check(y[0], y[1], y[2]))
					vec3.push_back(y[0]), vec3.push_back(y[1]), vec3.push_back(y[2]);
				if (vec3.size() > vec1.size())
					vec1 = vec3;
			}
			take(a, x, 12, ~p[i]);
			for (int j = 0; j < ql; j++) //枚举6选3状态
			{
				vec3.clear();
				take(x, y, 6, q[j]);
				if (check(y[0], y[1], y[2]))
					vec3.push_back(y[0]), vec3.push_back(y[1]), vec3.push_back(y[2]);
				take(x, y, 6, ~q[j]);
				if (check(y[0], y[1], y[2]))
					vec3.push_back(y[0]), vec3.push_back(y[1]), vec3.push_back(y[2]);
				if (vec3.size() > vec2.size())
					vec2 = vec3;
			}
			if (ans.size() < vec1.size() + vec2.size())
				ans = vec1, ans.insert(ans.end(), vec2.begin(), vec2.end());
		}
		printf("Case #%d: %d\n", ti, ans.size() / 3);
		for (int i = 0; i < ans.size(); i += 3)
			printf("%d %d %d\n", ans[i], ans[i + 1], ans[i + 2]);
	}

	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值