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

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

题目描述

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

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

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

输入输出格式

输入格式:

输入文件共有二行。

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

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

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

输出格式:

输出文件仅一行,表示要求的原始木棍的最小可能长度

输入输出样例
输入样例#1

9
5 2 1 5 2 1 5 2 1

输出样例#1

6

说明

2017/08/05

数据时限修改:

-#17 #20 #22 #27 四组数据时限500ms

-#21 #24 #28 #29 #30五组数据时限1000ms

其他时限改为200ms(请放心食用)

题目分析

这道题,应该看得出是用搜索吧.我们可以枚举要拼的木棍的长度去搜,但是在搜之前,有一个条件,就是得需要用总长度去除以这个枚举的长度,如果不能整除,那么我们就不能那这个去搜(毕竟拼出来的都要是相同长度的,对吧)
在搜索时,我们记录这几个东西:
一个是当前搜索的根数(也就是在搜第几根),
一个是现在在搜的这一根的长度,
还有一个是现在是在用哪一根小木棍去拼的.
然后分两种情况去讨论,一种是当你用一个长度为a[i]的木棍去拼的时候,加上之前的已经拼好的长度发现刚好符合现在枚举的要拼的长度,那么我们就开始搜下一个要拼的.另一种情况则是还没有达到要拼的长度,那么就继续拼.(应该算是很简单的一种搜索了)

程序代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int cnt,n,sum,num,ss;
int a[70],vis[70];
inline int read(){
    int x=0,w=1;char ch;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
    return x*w;
}
inline bool cmp(int a,int b){ return a>b; }
int dfs(int k,int len,int p){
//我们需要几个剪枝?k表示现在是在拼第几个,len是当前长度,p是这一次选的哪一个拼的,下一次从p+1开始
    bool flag=false;
    if(!len) flag=true;
    if(k==num) return true;
    for(register int i=p+1;i<=cnt;++i) {
        if(vis[i]) continue;
        if(len+a[i]==ss) {//分的两种情况,ss为当前要拼成的目标长度
            vis[i]=1; if(dfs(k+1,0,0)) return true;
            vis[i]=0; return false;
        }
        else if(len+a[i]<ss) {
                vis[i]=1; if(dfs(k,len+a[i],i)) return true;
                vis[i]=0; if(flag) return false;
 //回溯,这里用flag判断了一下,是因为如果连当前枚举的第一个最大长度小木棍都拼不了,那么小的就不用试了
                //那就不用搜索下去了.这应该叫做可行性剪枝吧.
                while(a[i]==a[i+1]) ++i;
                //如果遇上相同长度的木棍,直接跳过,不再尝试相同长度的
            }
    }
    return false;
}
int main(){
    n=read();
    for(register int i=1;i<=n;++i) 
        { int c=read(); if(c<=50) {a[++cnt]=c;sum+=a[cnt];} }
    sort(1+a,1+a+cnt,cmp);
    for(register int i=a[1];i<=sum;++i) {
        if((sum%i)) continue;ss=i;
        num=sum/i;memset(vis,0,sizeof(vis));
        if(dfs(1,0,0)){ printf("%d\n",i); return 0; }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tangzhide123yy/article/details/80008403