洛谷题单指南-进阶搜索-P1120 小木棍
原题链接:https://www.luogu.com.cn/problem/P1120
题意解读:将一组整数(小木棍)分组,使得每组之和(大木棍)一样,且分组数越多越好,求分组数最多是每组和(大木棒的最值长度)。
解题思路:
根据数据范围可以知道是一道搜索+剪枝题!
1、搜索顺序
对于本题,一个可行的搜索顺序是一组一组的搜,也就是设定一个大木棍的长度,然后从小木棍中拼出若干个大木棍,
对于大木棍的长度,可以通过从小到大枚举,但是必须是所有小木棍长度的约数才合法,
在挑选小木棍时,显然优先挑选长度长的,会减少搜索层级,因此可以将小棍木长度从大到小排序,
如果某个小木棍已经选了,后面再选小木棍时,应该从上次选过的小木棍之后来选,而不是从头选,
如果已经拼出了一根大木棍,则要从头开始拼下一根大木棍,
因此,dfs需要三个参数:a、cnt表示当前用了多少根大木棍, b、start表示从哪根小木棍开始拼 c、sum表示当前拼出的长度。
2、可行性剪枝
如果小木棍已经用过,则跳过;
如果当前已拼长度+当前小木棍长度超过了目标大木棍长度,则跳过;
4、减少重复冗余
如果当前小木棍不能使得最终拼出目标长度,那么接下来若干和当前小木棍长度相同的都不行,可以直接跳过;
如果当前小木棍作为大木棍的开头不能使得最终拼出目标长度,那么肯定无解;
如果当前小木棍作为大木棍的结尾不能使得最终拼出目标长度,那么肯定无解;
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 70;
int n, a[N], all, len;
bool flag[N];
//cnt表示当前用了多少根大木棍, start表示从哪根小木棍开始拼,sum表示当前拼出的长度
bool dfs(int cnt, int start, int sum)
{
if(cnt * len == all) return true;
if(sum == len) return dfs(cnt + 1, 1, 0); //如果当前拼出的长度等于len,那么就从第一根小木棍开始拼下一根大木棍
for(int i = start; i <= n; i++) //剪枝,从第start根小木棍开始拼,这样可以避免重复搜索
{
if(flag[i]) continue;
if(sum + a[i] > len) continue; //剪枝,如果当前拼出的长度加上当前木棍的长度大于len,那么就不用当前木棍
flag[i] = true;
if(dfs(cnt, i + 1, sum + a[i])) return true;
flag[i] = false;
if(sum == 0) return false; //剪枝,如果从头拼一根大木棍都拼不出来,那么就不用继续拼了
if(sum + a[i] == len) return false; //剪枝,如果当前小木棍是大木棍的最后一根且还不能得到解,那么就不用继续拼了
int j = i;
while(j <= n && a[j] == a[i]) j++; //剪枝,如果当前木棍和后面的木棍长度相同,那么就不用重复搜索
i = j - 1;
}
return false;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
all += a[i];
}
sort(a + 1, a + n + 1, greater<int>()); //从大到小排序,这样可以先拼长的木棍,减少搜索空间
for(int i = 1; i <= all; i++)
{
if(all % i == 0) //如果all能被i整除,那么就有可能拼出长度为i的木棍
{
memset(flag, 0, sizeof flag);
len = i;
if(dfs(0, 1, 0))
{
cout << len;
break;
}
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?