想看更多的解題報告:
http://blog.csdn.net/wangjian8006/article/details/7870410
轉載請註明出處:http://blog.csdn.net/wangjian8006
題目大意:給出一些短小的木棍,這些木棍是原本一些等長的原始木棍折斷而來的,將這些木棍組成等長的原始木棍,求出原始木棍的最小長度
解題思路:是poj2362的升級版本,利用搜索,不過這題時間卡的緊,需要進一步剪枝,具體剪枝看代碼註釋
但不知道爲何,用qsort交C就超時,不過改成sort後交C++就A了,這個經歷了1個小時調試出來的看出來的....
比較要注意的兩個剪枝:
剪枝1:
噹噹前的小木棍加上去,剛好可以找到一根原始木棍的時候。
這個時候有三種情況,1:這根木棍是組成這根原始木棍找得到答案,那麼返回1。
2:這個木棍不是組成這根原始木棍,那麼繼續找後面的小木棍,但是後面的小木棍全是比當前小木棍長度長的。所以並不符合,所以直接返回0,不用往後面搜索了
3:這個時候有可能回溯找比當前木棍小,能夠組成當前木棍的一些小木棍。但是在之後的搜索不可能會得到這些組合木棍的解(如果有解的話,早在之前就搜索了),所以直接返回0
剪枝2:
當原始木棍的未被找到的第一根小木棍去枚舉答案都不能組成這個原始木棍,這根小木棍必然不能組成後面的所有原始木棍,所以那麼直接返回0,不用往後面搜索
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXV 100
int nStickCount; //小木棍總數
int nStickLength[MAXV]; //保存小木棍長度
int nAns,nSum; //代表原始木棍最小長度和所有小木棍的總長度
int vis[MAXV]; //標記小木棍是否被找到
//int cmp(const void *a,const void *b)
int cmp(const int &a, const int &b){
return a > b;
//return *(int *)a-*(int *)b;
}
int dfs(int nNowBorderCount,int nExitBorder,int cur){ //分別代表,已經找到當前原始木棍大小,已經找到了多少原始木棍,搜到第幾根小木棍索引值
int i;
if(nExitBorder == nSum/nAns){ //如果已經存在的原始木棍,等於總長度除以原始木棍最小長度,那麼就代表已經搜索到答案,返回真
return 1;
}
for(i = cur;i < nStickCount;i++){
if(i && !vis[i-1] && nStickLength[i]==nStickLength[i-1]){ //如果前面一條木棍沒被取中,但是當前木棍長度等於前木棍長度,那麼不做處理,注意i不等於0,否則越界超時
continue;
}
if(!vis[i]){ //如果此木棍已經被找到,那麼不做處理
if(nNowBorderCount + nStickLength[i] < nAns){
vis[i] = 1;
if(dfs(nNowBorderCount + nStickLength[i],nExitBorder,i+1)){
return 1;
}
vis[i] = 0;
if(nNowBorderCount==0) return 0; //這裏返回0的意思看剪枝2
}else if(nNowBorderCount + nStickLength[i] == nAns){
vis[i] = 1;
if(dfs(0,nExitBorder + 1,0)){
return 1;
}
vis[i] = 0;
return 0; //這裏返回0的意思看剪枝1
}
}
}
return 0;
}
int main(){
int i;
while(scanf("%d",&nStickCount) && nStickCount){
nSum = 0;
for(i = 0;i < nStickCount;i++){
scanf("%d",&nStickLength[i]);
nSum += nStickLength[i];
}
//qsort(nStickLength,nStickCount,sizeof(int),cmp);
sort(nStickLength, nStickLength + nStickCount, cmp); //將小木棍從小到大排序
nAns = nStickLength[0]; //原始木棍的最小長度爲最小木棍的長度
while(nSum % nAns != 0) nAns++; //如果總長度對原始木棍的最小長度除不斷,那麼這個值肯定不是答案,那麼繼續往上加遍歷
memset(vis,0,sizeof(vis));
while(!dfs(0,0,0)){ //假設原始最小長度爲nAns,搜索,看小木棍是否可以組成nSum/nAns根原始木棍
nAns++; //遍歷nAns往上加,總會有答案,因爲當原始木棍只有1根的時候,那麼最小長度爲所有木棍之和
while(nSum % nAns != 0) nAns++;
memset(vis,0,sizeof(vis));
}
printf("%d\n",nAns);
}
return 0;
}