(hdu step 4.3.5)Sticks(将n根木棒合成若干根等长的木棒,求合成后的木棒的长度的最小值)
2015-02-25 12:57
330 查看
题目:
题目分析:
DFS。
代码如下:
/*
* e.cpp
*
* Created on: 2015年2月25日
* Author: Administrator
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 65;
bool visited[maxn];//用于标记某个木棒是否已经使用过
int values[maxn];//结果序列
bool flag;//用于标记使用已经成功找到一种方案
int parts;//标记木棒的份数
int len;//等长木棒的长度
int n;//原始木棒序列的根数
/**
* 深搜。
* pos:当前搜索的的木棒的索引
* cur:当前已经拼成的木棒的长度
* cnt:当前已经拼好的木棒的数量
*/
void dfs(int pos,int cur,int cnt){
if(cur == len){//如果当前木棒的长度==指定的木棒长度
cnt++;//拼好的木棒的数量+1
if(cnt == parts){//如果拼好的木棒数量==指定的木棒数量
flag = true;//将flag标记为true,表示已经成功
return ;//返回
}
//如果还没有拼够指定数量的等长木棒
dfs(0,0,cnt);//则继续拼
}
if(pos >= n){//如果当前搜索到的木棒的索引已经超出了木棒的范围
return ;//则返回,表示没有成功
}
int i;
for(i = pos ; i < n ; ++i){//从当前木棒开始向后扫
if(visited[i] == false && values[i] + cur <= len){//如果该根木棒没有被访问过&&当前木棒的长度+已经拼好的木棒的长度<=len
visited[i] = true;//则将该木棒标记为已经访问过
dfs(i+1,values[i]+cur,cnt);//在此基础上继续往下搜
visited[i] = false;//回滚
/**
* 剪枝。
* 如果当前已经找到一种方案,则返回
* pos的那个剪枝我也还没有想明白,没加的时候TLE.
*
*/
if(flag == true|| pos == 0){
return ;
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF,n){
int maxLen = -1;
int sum = 0;
int i;
for(i = 0 ; i < n ; ++i){
scanf("%d",&values[i]);
if(values[i] > maxLen){
maxLen = values[i];//计算所有木棒中的最大长度
}
sum += values[i];//计算所有木棒的总长度
}
/**
* 从单根木棒的最大长度开始枚举所有情况。
* 为什么从但根木棒的最大值开始枚举而不是从最小值开始枚举呢?因为最小值的情况下,
* 比最小值长度要大的木棒必然会被废弃.这很明显不符合题意
*/
for(len = maxLen ; len < sum ; ++len){
if(sum%len == 0){//如果该长度下,木棒能够被等分
memset(visited,false,sizeof(visited));
parts = sum/len;//计算该长度下能分成多少根木棒
flag = false;//重新将flag设置成false
dfs(0,0,0);//开始搜索
if(flag == true){//如果已经成功
break;//跳出循环
}
}
}
printf("%d\n",len);//输出找到的合成后的木棒的最小的长度
}
return 0;
}
Sticks |
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) |
Total Submission(s): 364 Accepted Submission(s): 116 |
[align=left]Problem Description[/align]George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero. |
[align=left]Input[/align]The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero. |
[align=left]Output[/align]The output file contains the smallest possible length of original sticks, one per line. |
[align=left]Sample Input[/align]9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0 |
[align=left]Sample Output[/align]6 5 |
[align=left]Source[/align]ACM暑期集训队练习赛(七) |
[align=left]Recommend[/align]lcy |
DFS。
代码如下:
/*
* e.cpp
*
* Created on: 2015年2月25日
* Author: Administrator
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 65;
bool visited[maxn];//用于标记某个木棒是否已经使用过
int values[maxn];//结果序列
bool flag;//用于标记使用已经成功找到一种方案
int parts;//标记木棒的份数
int len;//等长木棒的长度
int n;//原始木棒序列的根数
/**
* 深搜。
* pos:当前搜索的的木棒的索引
* cur:当前已经拼成的木棒的长度
* cnt:当前已经拼好的木棒的数量
*/
void dfs(int pos,int cur,int cnt){
if(cur == len){//如果当前木棒的长度==指定的木棒长度
cnt++;//拼好的木棒的数量+1
if(cnt == parts){//如果拼好的木棒数量==指定的木棒数量
flag = true;//将flag标记为true,表示已经成功
return ;//返回
}
//如果还没有拼够指定数量的等长木棒
dfs(0,0,cnt);//则继续拼
}
if(pos >= n){//如果当前搜索到的木棒的索引已经超出了木棒的范围
return ;//则返回,表示没有成功
}
int i;
for(i = pos ; i < n ; ++i){//从当前木棒开始向后扫
if(visited[i] == false && values[i] + cur <= len){//如果该根木棒没有被访问过&&当前木棒的长度+已经拼好的木棒的长度<=len
visited[i] = true;//则将该木棒标记为已经访问过
dfs(i+1,values[i]+cur,cnt);//在此基础上继续往下搜
visited[i] = false;//回滚
/**
* 剪枝。
* 如果当前已经找到一种方案,则返回
* pos的那个剪枝我也还没有想明白,没加的时候TLE.
*
*/
if(flag == true|| pos == 0){
return ;
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF,n){
int maxLen = -1;
int sum = 0;
int i;
for(i = 0 ; i < n ; ++i){
scanf("%d",&values[i]);
if(values[i] > maxLen){
maxLen = values[i];//计算所有木棒中的最大长度
}
sum += values[i];//计算所有木棒的总长度
}
/**
* 从单根木棒的最大长度开始枚举所有情况。
* 为什么从但根木棒的最大值开始枚举而不是从最小值开始枚举呢?因为最小值的情况下,
* 比最小值长度要大的木棒必然会被废弃.这很明显不符合题意
*/
for(len = maxLen ; len < sum ; ++len){
if(sum%len == 0){//如果该长度下,木棒能够被等分
memset(visited,false,sizeof(visited));
parts = sum/len;//计算该长度下能分成多少根木棒
flag = false;//重新将flag设置成false
dfs(0,0,0);//开始搜索
if(flag == true){//如果已经成功
break;//跳出循环
}
}
}
printf("%d\n",len);//输出找到的合成后的木棒的最小的长度
}
return 0;
}
相关文章推荐
- (hdu step 1.3.6)Wooden Sticks(求长度和重量都严格递增的数列的个数)
- HDU 1455 Sticks(DFS,剪枝,原来木棒的至少长度)
- (step 4.3.5)hdu 1035(Robot Motion——DFS)
- (step4.3.5)hdu 1501(Zipper——DFS)
- (step6.1.5)hdu 1233(还是畅通工程——最小生成树)
- (step6.3.3)hdu 1150(Machine Schedule——二分图的最小点覆盖数)
- hdu2870子串长度子串最小数
- (hdu step 4.2.7)Kill the monster(有n个技能,求杀死怪物的技能的最小使用次数。在使用某一个技能的时候,如果怪物的能量值hp<=m,这时候造成的伤害值是原来的两倍)
- (step6.1.8)hdu 3367(Pseudoforest——最小生成树的逆应用)
- (step6.1.7)hdu 3371(Connect the Cities——最小生成树)
- (hdu step 4.2.3)Knight Moves(求从起点是否能够到达终点的最小步数)
- (step 4.3.5)hdu 1035(Robot Motion——DFS)
- (step6.1.3)hdu 1875(畅通工程再续——最小生成树)
- (step6.1.2)hdu 1863(畅通工程——最小生成树)
- (step 6.1.9)hdu 1162(Eddy's picture——最小生成树)
- (step4.3.5)hdu 1501(Zipper——DFS)
- (step6.1.1)hdu 1879(继续畅通工程——最小生成树、kruscal)
- (step6.1.3)hdu 1875(畅通工程再续——最小生成树)
- (step6.3.4)hdu 1151(Air Raid——最小路径覆盖)
- (hdu step 4.2.4)A strange lift(求从起点到终点的最小步数,限制条件是:在一维的情况下)