/*此题是经典的dfs,一般都需要剪枝,思想主要是首先,明确最短的长度肯定是>=样例中最长的,最长的是所有样例的数字加和。其次,通过深搜,从最短到最长一次遍历深搜就可得到最短的,深搜的思想看代码可知*/
/*做这种题思路清晰后写题有个技巧,边写将注释都写清楚方便梳理思路,思路很重要思路确定后在集中解决边界等情况,因为dfs每一步的回溯都需要很清楚,不能乱*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, a[200], visit[200], ss, sum;//sum将所有长度的棍子长度加和。ss是终止判断申请的变量下面将会有解释
bool cmp(int a, int b){
return a>b;
}
void dfs(int maxx, int pos, int value, int num)//maxx为当前的目标长度,pos为当前的位置,value为当前棍子的长度并非目标棍子的长度,num为以sum为总长度,maxx为目标长度的个数;
{
if(ss == 1)return;//剪枝是必须要加的不然总是超时
if(value == maxx){//这里是判断若当前长度和目标长度相等时进行接下来的操作判断是否能够输出
num++;
if(sum/maxx == num){//这里是为了输出坐的做后的判断符合输出的条件是ss==1,只有当每次几根棍子长度的组合相等,且,每与目标长度相等一次加加若恰好加加次数与(总长度/目标长度)相等则恰好满足(因为会存在只与目标长度相等但是次数并不相等的情况)这才是真正的终止条件
ss = 1;
return;
}
dfs(maxx, 0, 0, num);
return;
}
if(pos == n)return;
for(int i = pos; i < n; i++){// 以下是主要的遍历的过程遍历的规则是已经用过的棍子不能再用,当前累加的棍子的长度小于等于从greedy函数传来的当前的棍子的长度;
if(!visit[i] && a[i] + value <= maxx){
visit[i] = 1;
dfs(maxx, i + 1, value + a[i], num);
visit[i] = 0;
if(pos == 0)return;//这里的剪枝必须加不然超时确定每次搜索的起始位置
}
}
}
int greedy(int maxm, int sum){//棍子长度的组合并不是两个两个组合会有很多种情况用这个函数解决
int k = 0, res[1000];
for(int i = maxm; i < sum; i++){//res数组为棍子长度的可能但并不是所有的可能都会符合题目的样例样例所得到的长度定是从res中提取的,k为可能的个数
if(sum % i == 0) {
res[k] = i;
k++;
}
}
for(int j = 0; j < k; j++){//将所有长度的棍子枚举与样例中所给的数据进行匹配
memset(visit, 0, sizeof(visit));
ss = 0;
dfs(res[j], 0, 0, 0);//这里是将长度从最小到最大枚举一旦符合题目便是最小的长度
if(ss == 1) return res[j];//这里只是规定一下,什么时候符合题目要求并输出;
}
return sum;//若枚举中并没有找到符合题目的没有与之匹配的长度,则最短长度必然是棍子的总长度;
}
int main()
{
while(scanf("%d", &n) != EOF && n){
sum = 0,ss = 0;
int maxx = 0;//定义一个当前最的目标长度stick的变量;
memset(a, 0, sizeof(a));
memset(visit, 0, sizeof(visit));
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
if(maxx < a[i]) maxx = a[i];
sum += a[i];
}
sort(a, a+n, cmp);
printf("%d\n", greedy(maxx, sum));
}
return 0;
}//博主做的心累啊提交过了以后改了改结果怎么都过不去改了快有10次又从新写了一次不负有心人过了,看到的同学加油写吧不要急静下来事半功倍;
hdu1455sticks
最新推荐文章于 2024-09-17 14:09:50 发布