洛谷P1120 小木棍 [数据加强版]


3个月前写过一遍,现在回来复习。当时自己写暴力好像只有10几分,现在自己写剪枝有54分,再加上一个优化就可以过了

剪枝策略:

①把木棍降序排列,因为长度短的木棍可以组成大的木棍,而大的木棍无法拆分成小的木棍。由于每个木棍都得拼上,如果先小后大,导致好几个小的加起来等于某一个大的,这样就可能让失败状态搜索树拓展两次。所以优先拼大木棍状态数减少。

②拼每一根木棍时记录已经失败的长度。由于小木棍的长度可能相同,对每个长度只搜索一次

③就是少了这一点没能过。if (mu[i] + now == len || now == 0)return;对于这种失败情况,可以直接return,因为len-mu[i]这个长度不管怎么拼之后都是失败的


#include
#include
#include

using namespace std;
const int inf = 1e9;
const int maxn = 1e5 + 10;
int n, sum = 0, maxmu = 0;
int mu[70];
int used[70];

void dfs(int now,int cnt,int last,int len)
{
	if (now == len)
	{
		dfs(0, cnt + 1, 1, len);
		return;
	}
	if (cnt == sum / len)
	{
		cout << len;
		exit(0);
	}
	int fail = 0;
	for (int i = last; i <= n; i++)
	{
		if (mu[i] == fail)continue;
		if (!used[i] && now + mu[i] <= len)
		{
			used[i] = 1;
			dfs(now + mu[i], cnt, i + 1, len);
			used[i] = 0;
			fail = mu[i];
			if (mu[i] + now == len || now == 0)return;
		}
	}
}

bool cmp(int x, int y)
{
	return x > y;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> mu[i];
		if (mu[i] > 50)n--, i--;
		else { 
			sum += mu[i]; 
			maxmu = max(maxmu, mu[i]);
		}
	}
	sort(mu + 1, mu + n + 1, cmp);
	for (int i = maxmu; i <= sum; i++)
	{
		if (sum % i)continue;
		dfs(0, 0, 1, i);
	}
	return 0;
}