牛客
鏈接:https://ac.nowcoder.com/acm/problem/50243
來源:牛客網(wǎng)
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述
喬治有一些同樣長的小木棍,他把這些木棍隨意砍成幾段,直到每段的長都不超過50。現(xiàn)在,他想把小木棍拼接成原來的樣子,但是卻忘記了自己開始時有多少根木棍和它們的長度。給出每段小木棍的長度,編程幫他找出原始木棍的最小可能長度。
輸入描述:
第一行為一個單獨的整數(shù)N表示砍過以后的小木棍的總數(shù)。第二行為N個用空格隔開的正整數(shù),表示N根小木棍的長度。
輸出描述:
輸出僅一行,表示要求的原始木棍的最小可能長度。
示例1
輸入
9
5 2 1 5 2 1 5 2 1
輸出
6
備注:
1<=N<=60
題目大意:
給出n個小木棍,你的任務(wù)是把他們拼接起來,還原原來的木棍,求拼接后每個小木棍的最小長度。
解題思路:
這個題注意一定要用搜索做而不是二分,之前做過一個拆分木棍的題是二分,因為那個題長度和拆分的數(shù)量有一個線性關(guān)系,而這個合并木棍并沒有,我們用DFS+剪枝AC這個題,因為要求最小的長度,我們先將木棍排序,因為要求拼成的最小的長度,我們要從這些木棍最長的開始往上枚舉,對每一個枚舉的長度進(jìn)行搜索,搜索的狀態(tài)是(剩余木棍的個數(shù),枚舉的長度,當(dāng)前拼成木棍剩余長度,和當(dāng)前枚舉的哪一根木棍)另外需要剪枝操作,剪枝有以下幾點:
如果當(dāng)前木棍是當(dāng)去拼枚舉長度的第一根,則需要剪掉,因為我們從最長的開始枚舉,如果連第一個都拼不上,那么后面的肯定也拼不上。如果當(dāng)前木棍是當(dāng)去拼枚舉長度的最后一根,也需要剪掉,因為木棍是從大到小排,如果這個長度都不行,那后面的長度肯定比這個還小,肯定也拼不上,剪掉。如果當(dāng)前小木棍拼不上,那么和當(dāng)前木棍長度相同的木棍肯定也拼不上,直接過濾掉和當(dāng)前木棍長度相等的木棍即可。
AC代碼:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 65;
int a[N],n;
bool vis[N];
bool cmp(int a,int b) { return a>b; }
bool dfs(int num,int len,int rest,int now)
{
if(num==0&&rest==0)//當(dāng)前剩余0個木棍且當(dāng)前要拼的長度為0時代表可以拼成
return true;
if(rest==0)
rest=len,now=0;
for(int i=now;i<n;i++)
{
if(a[i]>rest)
continue;
if(!vis[i])
{
vis[i]=true;
if(dfs(num-1,len,rest-a[i],i+1))
return true;
vis[i]=false;
if(a[i]==rest||len==rest)//第一個木棍和最后一個木棍的時候剪掉
break;
while(a[i]==a[i+1])//過濾掉相同的木棍
i++;
}
}
return false;
}
int main()
{
int sum=0,s=0;
scanf("%d",&n);
memset(vis,false,sizeof vis);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(a[i]<=50)
sum+=a[i];
else
s++;
}
n-=s;
sort(a,a+n,cmp);
for(int i=a[0];i<=sum;i++)//從最大的開始枚舉
{
if(sum%i==0)
if(dfs(n,i,0,0))
{
printf("%d
",i);
break;
}
}
return 0;
}
總結(jié)
- 上一篇: Linux服务器 | 服务器模型与三个模
- 下一篇: iOS音频播放(一):概述