小木棍

題目描述(洛谷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. .顯然枚舉全部狀況再用遞歸判斷是否可行很浪費時間,再輸入數據時統計sum,當g,k都爲整數時在調用遞歸判斷是否可行;
  2.  顯然枚舉全部狀況再用遞歸判斷是否可行很浪費時間,再輸入數據時統計sum,當g,k都爲整數時在調用遞歸判斷是否可行;
  3. 從剩下的小木棍從大到小挑選出第一個不大於n的小木棍進行拼接,eg(挑5,有5,3,2確定挑5),將較小較靈活組合的小木棍留下來。注意:當挑6,有5,4,2,1,有些木棍拼接須要1,因此有時要選4,2,不能因挑走5後,剩下的木棍沒法拼接就終止以k爲最小長度的遞歸判斷。
  4. 當n=k時,向下一層dfs(k,n–i(當前選中木棍長度),c)返回失敗時,直接向上一層返回失敗。(c爲已拼接好的段數)由於當前要從新開始拼接新的長度爲k的一段,下一層返回失敗即當前選擇的這根與剩下的小木棍沒法拼接成長度爲k的一段,直接返回失敗。
  5. 當n=i(當前選中木棍長度),向下一層dfs(k,k,c+1)返回失敗時,直接向上一層返回失敗。
  6. 輸入數據時,記下最大的小木棍長度maxa,主函數枚舉時直接從maxa枚舉最小長度(枚舉段數沒有這樣優點了)。 大概就是這樣迭代枚舉長度,符合都是整數,調用dfs(flag爲標記)

 

 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.  不必枚舉長度循環到sum,而是sum/2,即 **for(int i=maxa;i<=sum/2;++i)**當迭代結束後,flag=1輸出當前循環的i,不然輸出sum。
  2. 還沒完,範圍優化,在錄入數據時,記下有效數據最大值maxa,最小值mina,再向dfs中加入開始枚舉的最大長度q,則對特殊數據有很大的優化效果。
  3. 不使用flag,在獲得結果時還要在層層返回,浪費時間,直接打印k,exit(0);不然在最後就回到了主函數直接輸出sum。
  4. 其實還能夠手寫輸入代碼。直接上源代碼
 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 }
View Code
相關文章
相關標籤/搜索