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

原题链接:https://www.luogu.com.cn/problem/P1120

P1120 小木棍 [数据加强版]

题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50

现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式

共二行。

第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65

(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)

第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

输出格式

一个数,表示要求的原始木棍的最小可能长度

输入输出样例

输入 #1
9
5 2 1 5 2 1 5 2 1
输出 #1
6



这个题目是一个搜索题,主体思路就是从小到大枚举每一个长度然后验证是否满足条件,但直接暴力搜索会超时,需要对其进行优化。
https://www.luogu.com.cn/record/30758332

(这是暴力搜索的代码,只得了18分)
#include<stdio.h>
int a[51],b[51];
int n,s,ye=0,ans=0,cs;
void ss(int a1,int a2){
    if(ye)return;
    int k=1;
    for(int i=1;i<=50;i++)if(a[i]){k=0;}
    if(k!=0&&a2==0){ans=1;ye=1;}
    if(a2==0)ss(a1+1,cs);
    for(int i=1;i<=a2;i++)if(a[i]){
        a[i]--;
        ss(a1,a2-i);
        a[i]++;}
    return;}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&s);
        if(s>50)continue; 
        b[s]++;a[s]++;
    }
    for(int i=1;i<=3250;i++){
        ye=0;ans=0;cs=i;
        ss(0,cs);
        if(ans){printf("%d",i);return 0;}
    }
        return 0;}

经过本人的反复摸索(并且借鉴了dalao的解法)终于找到了几个优化办法:


  1.搜索时从大到小枚举;

  2.若拼接当前木棍时已用了一根长为X的木棍,则下一次搜索时从长度X开始搜索,尽量减少重复搜索;

  3.枚举的长度应该是所有木棍总长度的因数;

  4.若某组拼接不成立,且此时已拼接的长度为0或当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案时,则可直接跳出循环,因为此时搜索结果是不成立,那么继续搜索得到的也不成立;

  5.用桶来存储可能更好,因为范围是1-50。

经过优化,得到了100分。

https://www.luogu.com.cn/record/30758337

最后附上AC代码。

C/C++:

#include<stdio.h>
int a[51];
int n,s,ye=0,ans=0,cs,maxx=0,zong=0;
int minn(int a1,int a2){
    return a1<a2?a1:a2;}
void ss(int a1,int a2){
    if(ye)return;
    int k=1;
    for(int i=1;i<=maxx;i++)if(a[i]>0){k=0;break;}
    if(k!=0&&a2==0){ans=1;ye=1;}
    if(a2==0)ss(maxx,cs);
    for(int i=minn(a1,a2);i>0;i--)if(a[i]>0){
        a[i]--;
        ss(i,a2-i);
        a[i]++;
        if(a2==cs||a2==i)break;
        }
    return;}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&s);
        if(s>50)continue;
        a[s]++;
        zong+=s;
        if(s>maxx)maxx=s;
    }
    for(int i=maxx;i<=zong;i++)if(zong%i==0){
        ye=0;ans=0;cs=i;
        ss(maxx,cs);
        if(ans){printf("%d",i);return 0;}
    }
        return 0;}

Pascal:

  

var
    a:array[0..51]of longint;
    n,s,cs,maxx,zong:longint;
    ye,ans:boolean;
function minn(a1,a2:longint):longint;
begin
    if a1<a2 then exit(a1)
    else exit(a2);
end;
procedure ss(a1,a2:longint);
var 
    k:boolean;
    i:longint;
begin
    if ye then exit();
    k:=true;
    for i:=1 to maxx do
    begin 
        if a[i]>0 then
            begin
                k:=false;
                break;
            end;
    end;
    if(k=true)  and (a2=0) then
    begin
        ans:=true;
        ye:=true;
        exit();
    end;
    if a2=0 then ss(maxx,cs);
    for i:=minn(a1,a2) downto 1 do
    begin
        if a[i]>0 then
        begin
            a[i]:=a[i]-1;
            ss(i,a2-i);
            a[i]:=a[i]+1;
            if(a2=cs)  or (a2=i) then break;
        end;
    end;
    exit();
end;
var
    j:longint;
begin
    ye:=false;
    ans:=false;
    maxx:=0;
    zong:=0;
    readln(n);
    for j:=1 to n do
    begin
        read(s);
        if s>50 then continue;
        a[s]:=a[s]+1;
        zong:=zong+s;
        if s>maxx then maxx:=s;
    end;
    for j:=maxx to zong do
    begin
        if (zong mod j)=0 then
        begin
            ye:=false;
            ans:=false;
            cs:=j;
            ss(maxx,cs);
            if ans then 
            begin 
                writeln(j);
                break;
            end;
        end;
    end;
end.
 

如果有什么问题,请在评论区指出,谢谢。

猜你喜欢

转载自www.cnblogs.com/sy666/p/12324148.html
今日推荐