题目来源:http://poj.org/problem?id=1011
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 122460 | Accepted: 28373 |
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
Source
题意:
若干根相同长度的的棍子被随机分割,给出被分割后所有棍子各自长度,求原先棍子最短可能长度。
题解:
经典DFS,重在剪枝。看了题解才过的=== 首先对棍子长度由大到小进行排序,再DFS之。
剪枝一:
不要在同一个位置多次尝试相同长度的棍子
剪枝二:
1.如果由于以后的拼接失败,需要重新调整第i根棍子的拼法,则不会考虑替换第i根棍子中的第一根棍子(换了也没用)
2.如果在不替换第一根木棒的情况下怎么都无法成功,那么就要推翻第i-1根棍子的拼法。
3. 如果不存在第i-1根棍子,那么就推翻本次假设的棍子长度,尝试下一个长度
剪枝三:
不要希望通过仅仅替换已拼好棍子的最后一根棍子就能够改变失败的局面。
剪枝四:
拼每一根棍子的时候,应该确保已经拼好的部分,长度是从长到短排列的。
AC代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int used[65],n,stick[65],last,sum,Len;
bool dfs(int r,int left)
{
if(!r&&!left) return true;
if(!left) left=Len;
int star=0;
if(left!=Len) star=last+1; //剪枝四
for(int i=star;i<n;i++)
{
if(!used[i]&&stick[i]<=left){
if(i>0&&!used[i-1]&&stick[i-1]==stick[i])
continue; //剪枝一
used[i]=1;last=i;
if(dfs(r-1,left-stick[i])) return true;
else {
used[i]=0;
if(stick[i]==left||left==Len)
return false; //剪枝二、三
}
}
}
return false;
}
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
cin.sync_with_stdio(false);
while(cin>>n,n)
{
sum=0;
for(int i=0;i<n;i++){
cin>>stick[i];
sum+=stick[i];
}
sort(stick,stick+n,cmp);
for(Len=stick[0];Len<=sum;Len++)
{
if(sum%Len) continue;
memset(used,0,sizeof(used));
if(dfs(n,Len)){
cout<<Len<<endl;
break;
}
}
}
return 0;
}
原文地址:http://blog.csdn.net/mummyding/article/details/41013141