蓝桥杯 算法训练 Sticks

问题描述
  George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
输入格式
  The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
输出格式
  The output should contains the smallest possible length of original sticks, one per line.

解题思路
点击链接,这位大神讲的十分详细了!!!

我的理解
总体思路:
1.题目通过所有值求和为sum,整数i从最大值max到sum,若sum%i=0,则i为可能解。
2.通过递归验证所给木棒是否能组成长度为i的多条木棒。

递归验证思路:
递归有三个参数:1. nowLen:表示当前木棒的长度,2.nowGet表示现在已经拼接的木棒数,3.cnt表示下一个寻找树枝的下标。

递归思路:
如果cnt>n,则返回0。因为下标超了。
如果nowGet=g,则返回1。表示所有的木棒都用完了,成功。
i从cnt到n一次寻找stick[i]是否符合下面两种情况的一种。

1.nowLen+sticks[i].length ==len,表示已经拼成一根完整的木棒,则更新当前木棒数,进行新一根木棒的拼接。
2.nowLen+sticks[i].length<len,表示当前木棒可能能够拼成一根完整的木棒,则更新木棒长度,继续进行木棒拼接。

剪枝条件
1.如果有一根木棒加上去,找不到其他木棒可以和其拼成一整根木棒,则该策略是完全无效的,直接返回0。
2.如果当前木棒不满足要求,则和它等长的木棒一定不满足要求,直接跳过。

代码部分

#include <stdio.h>
#include <algorithm>
using namespace std;
#define USED 1
#define UNUSED 0
#define MAXSIZE 64

struct Stick
{
    int length;
    int mark;
}sticks[MAXSIZE];

bool cmp(Stick a,Stick b){
    return a.length>b.length;
}

int n;
int g;
int len;

int DFS(int nowLen,int nowGet,int cnt)
{
    if(cnt>=n) return 0;
    if(nowGet == g) return 1;
    int i;
    for(i=cnt;i<n;i++)
    {
        if(sticks[i].mark==UNUSED)
        {
            if(nowLen+sticks[i].length==len)
            {
                sticks[i].mark = USED;
                if(DFS(0,nowGet+1,nowGet)==1)
                {
                    return 1;
                }
                sticks[i].mark = UNUSED;
                return 0;
            }
            else if(nowLen+sticks[i].length<len)
            {
                sticks[i].mark = USED;
                if(DFS(nowLen+sticks[i].length,nowGet,i+1)==1)
                {
                    return 1;
                }
                sticks[i].mark=UNUSED;
                if(nowLen==0)return 0;
                for(;sticks[i].length==sticks[i+1].length&&i+1<n;i++);
            }
        }
    }
    return 0;
}
int main(){
    int i;
    int sum;
    //scanf("%d",&n);
    while(scanf("%d",&n)!=EOF&&n!=0){
        for(i=0;i<MAXSIZE;i++)
        {
            sticks[i].mark=UNUSED;
        }
        sum=0;
        for(i=0;i<n;i++){
            scanf("%d",&sticks[i].length);
            sum+=sticks[i].length;
        }
        //printf("???\n");
        sort(sticks,sticks+n,cmp);
        //printf("%d\n",sticks[0].length);
        for(len=sticks[0].length;len<=sum;len++)
        {
            if(sum%len!=0)continue;
            g=sum/len;
            if(DFS(0,0,0))
            {
                break;
            }
        }
        printf("%d\n",len);
    }
    return 0;
}

代码说明
在大神原有的代码基础上,我用algorithm中已有的排序算法代替了大神手写的冒泡排序。递归判定部分则照搬了源码。

今天也是个菜鸡啊啊啊啊,博客也没人看。
emmm,开心就好,继续加油

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小郁同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值