poj1011 - Sticks

来源:互联网 发布:手机发热软件 编辑:程序博客网 时间:2024/05/18 03:01

                                想看更多的解题报告: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 100int 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;}