这道题在两个OJ上都有
POJ地址
http://poj.org/problem?id=1011
HDU地址
http://acm.hdu.edu.cn/showproblem.php?pid=1455
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 129296 | Accepted: 30304 |
Description
Input
Output
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
题目大意
给你一些短的木棒拼成相同长度的长的木棒,问你所能拼成的木棒最短的长度
思路
用到多次的剪枝;
剪枝一:棍子L的长度一定会被所有棍子总和ntot整除,不能整除的减掉;
剪枝二:用lasttickno记录上次的最后一根棍子的序号,下次从lasttickno+1开始;
剪枝三:如果某次拼接选择长度为S 的木棒,导致最终 失败,则在同一位置尝试下一根木棒时,要跳 过所有长度为S 的木棒 ;
剪枝四: 如果在不替换第一根木棒的情况下怎么都无法成 功,那么就要推翻第i-1根棍子的拼法
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int N,l,s; int vis[65],len[65]; int sum; int laststickno; int dfs(int r,int m)//r为所剩的棍子的个数, m表示当前正在拼的棍子和 l 比还缺的长度 { if(r==0&&m==0) return true; if(m==0) m=l; int startno=0; if(m!=l) startno=laststickno+1;//剪枝2 for(int i=startno;i<s;i++){ if(!vis[i]&&len[i]<=m){ if(i>0){ if(vis[i-1]==false&&len[i]==len[i-1])//剪枝3 continue; } vis[i]=1; laststickno=i; if(dfs(r-1,m-len[i])) return true; else{ vis[i]=0; if(len[i]==l||m==l) return false; } } } return false; } int main() { while(cin>>s&&s) { laststickno=s-1; int ntot=0; memset(vis,0,sizeof(vis)); memset(len,0,sizeof(len)); for(int i=0;i<s;i++){ scanf("%d",&len[i]); ntot+=len[i]; } sort(len,len+s); for(l=len[0];l<=ntot/2;l++){ if(ntot%l) continue; memset(vis,0,sizeof(vis)); if(dfs(s,l)){ cout<<l<<endl; break; } } if(l>ntot/2) cout<<ntot<<endl;//剪枝4 } return 0; }