題目描述(洛谷1120)c++
喬治有一些一樣長的小木棍,他把這些木棍隨意砍成幾段,直到每段的長都不超過50,編程
如今,他想把小木棍拼接成原來的樣子,可是卻忘記了本身開始時有多少根木棍和它們的長度。ide
給出每段小木棍的長度,編程幫他找出原始木棍的最小可能長度。函數
思路
這題明顯是一段一段拼接,要使用廣搜或深搜,用廣搜則必然致使時間浪費,當拼不上則應當即調整上一狀態,則同級狀態也應改變,用廣搜明顯不合適。因此深搜用遞歸。
由於小於等於50,首先想到了桶排序;用其餘排序有些麻煩,由於須要不斷排序與增刪小木棍,當次數過多顯然耗時過多,有sort函數也不划算。
. 枚舉最多可能段數或最小可能長度。不論枚舉段數仍是長度,都要事先把預獲得的長度或段數計算出來,而後遞歸。天然想到,k爲最小可能長度,g爲最大可能段數,用當前還差n個長度的就拼好一段(也可用當前段已拼接的長度)去遞歸是好實現的。即dfs(int k,int n,int c);(c爲當前已拼接長度) 當n=0,dfs(k,k,c+1)便可,當c=g,則因爲循環順序,答案已出。優化
優化(dfs)spa
1 void work(int k,int n,int c){ 2 if(c==g) flag=1; 3 if(!n) {work(k,k,c+1);return;} 4 for(int i=50;i>0&&!flag;--i){ 5 if(lenth[i]&&i<=n) { 6 --lenth[i]; 7 work(k,n-i,c); 8 ++lenth[i]; 9 if(n==k||n==i) return; 10 } 11 } 12 }
然而仍是會超時的,洛谷數據更新了!!!!code
再優化blog
1 #include<bits/stdc++.h> 2 using namespace std; 3 int N,sum,maxa,g,mina=69; 4 int tiao[55]; 5 void read(){ 6 scanf("%d",&N); 7 for(int i=1,j=0;i<=N;++i){ 8 int x;scanf("%d",&x); 9 if(x>50)continue; 10 sum+=x; 11 if(x>maxa) maxa=x; 12 if(x<mina)mina=x; 13 tiao[x]++; 14 } 15 } 16 17 void work(int k,int n,int c,int q){ 18 if(c==g) {printf("%d",k);exit(0);}; 19 if(!n) {work(k,k,c+1,maxa);return;} 20 for(int i=q;i>=mina;--i) 21 if(tiao[i]&&i<=n) { 22 --tiao[i]; work(k,n-i,c,i);++tiao[i]; 23 if(n==k||n==i) return ; 24 } 25 } 26 27 int main(){ 28 read(); 29 N=sum>>1; 30 for(int i=maxa;i<=N;++i){ 31 if(sum%i==0){ 32 g=sum/i; 33 work(i,i,0,maxa); 34 } 35 } 36 printf("%d",sum); 37 return 0; 38 }