洛谷P1120信息奥赛一本通1442 小木棍

原题链接:

洛谷https://www.luogu.com.cn/problem/P1120

信息奥赛一本通http://ybt.ssoier.cn:8088/problem_show.php?pid=1442



这个题目是一个搜索题,主体思路就是从小到大枚举每一个长度然后验证是否满足条件,但直接暴力搜索会超时,需要对其进行优化。
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:

#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.
 

如果有什么问题,请指出,谢谢。

原文地址:https://www.cnblogs.com/sy666/p/12324148.html