Sticks(poj1011/uva307)

题目大意:

乔治有一些碎木棒,是通过将一些相等长度的原始木棒折断得到的,给出碎木棒的总数和各自的长度,求最小的可能的原始木棒的长度;(就是将一些正整数分组,每组加起来和相等,使和尽可能小)

一开始做poj 32ms过,但uva3000 ms 都超时。。。而且poj discuss里给出了一组bT数据,最后uva 0.2sac的代码也跑了3 。4秒左右。discuss里的大牛据说什么奇偶性剪枝0.01ms过,可惜搜了半天也没找到具体方法。这题就这样过好了。。(参考各种空间博客才艰难ac。不过此题实在是太经典了,搜索学习剪枝必做)

对于这道题而言,剪枝的策略一般有下面6个:

①先将木棒长度从大到小进行排序,这样便于后面的选择和操作,是后面一些剪枝算法的前提。

②在枚举原木棒长度时,枚举的范围为max与sum/2之间,如果这个区间内没有找到合适的长度,那么最后原木棒的长度只能是sum。

③枚举的原木棒的长度只能是sum的约数。

④在深搜过程中,如果当前木棒和前一个木棒的长度是一样的,但是前一个木棒没有被选上,那么这个木棒也一定不会被选上。

⑤在深搜过程中,如果当前是在拼一根新木棒的第一截,但如果把可用的最长的一根木棒用上后不能拼成功的话,那么就不用再试后面的木棒了,肯定是前面拼的过程出了问题。

⑥在深搜过程中,如果当前可用的木棒恰好能补上一根原木棒的最后一截,但用它补上之后却不能用剩下的木棒完成后续的任务,那么也不用再试后面的木棒了,肯定是前面拼的过程出了问题。

参考博客:http://www.cnblogs.com/staginner/archive/2011/09/08/2171329.html

我的ac 代码:(剪枝见注释)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

#include<cstdio>

#include<algorithm>

#include<cstring>

using namespace std;

int n,max_len,min_len,sum,ans,num,flag;

int a[10000],v[10000];

bool cmp(const int &x,const int &y)

{

return !(x<y);

}

void search(int step,int from,int cur)//step表示当前去凑的是第几根原始棒,order表示当前用了多少根碎棒子来凑第step根

{

//printf("%d %d\n",step,cur);

if (cur==ans)

{

if (step==num)

{

flag=1;

return;

}

int k;

for (k=1;k<=n && v[k];k++);

v[k]=1;

search(step+1,1,a[k]);

v[k]=0;

return;

}

for (int i=from;i<=n;i++)

{

if (v[i])

continue;

if (cur+a[i]>ans)

continue;

if (a[i]==a[i-1] && !v[i-1])

continue;//剪枝3:上一根棒和目前这根一样并且没用过,那么用这一根去凑和用上一根去凑结果一样都不能出解

//printf("kk %d %d\n",cur,cur+a[i]);

int t=a[i]+cur;

if (t!=ans && t+min_len>ans)

continue;

v[i]=1;

search(step,i+1,t);

v[i]=0;

if (t==ans)

return;

if (flag || cur==0)//剪枝4:如果当前用了1根碎棒子来凑,枚举了第一根碎棒不能出解那么跳出

return;

}

return;

}

int main ()

{

while (scanf("%d",&n)==1)

{

if (n==0)

break;

v[0]=1;

a[0]=210000000;

max_len=-1;

min_len=21000000;

sum=0;

flag=0;

for (int i=1;i<=n;i++)

{

scanf("%d",&a[i]);

if (a[i]>max_len)

max_len=a[i];

if (a[i]<min_len)

min_len=a[i];

sum+=a[i];

}

sort(a+1,a+n+1,cmp);

for (ans=max_len;ans<=sum/2;ans++)//剪枝1:答案的下界为最长的棒,上界为长度总和

{

if (sum%ans!=0)

continue;//剪枝 2:原始棒长度是总长度的约数

for (int k=1;k<=n;k++)

v[k]=0;

num=sum/ans;

search(1,1,0);

if (flag)

{

printf("%d\n",ans);

break;

}

}

if (!flag)

printf("%d\n",sum);

}

return 0;

}

Sticks(poj1011/uva307)

时间: 2024-08-29 16:15:16

Sticks(poj1011/uva307)的相关文章

UVA - 10003Cutting Sticks(递推)

题目:UVA - 10003Cutting Sticks(递推) 题目大意:给根木棍长度l,现在要锯这根木棍,给出n个锯点,求怎样锯才能使得开销最小.例如 长度为10的木棍, 锯点2 4 7,那么如果按照这个顺序 , 首先显示由长度位10的木头先锯了2 ,开销就加10,然后锯完现在有[0,2]和[2,10]长度分别为2 ,8的木棍,现在要在4这个位置锯木头,就是在长度为8的木头上锯4这个位置,这样就加上8,然后又有长度为[2,4][4,10]的木头,最后要锯7的话,就需要开销加上6.所以开销就是

poj-1011 sticks(搜索题)

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 h

UVA-307 Sticks (DFS+剪枝)

题目大意:用n根长度未必相等的木棒匹配出最多数量的等长木棒. 题目分析:枚举所有可能的等长木棒的长度,通过DFS的方式逐根匹配,在此过程中要剪枝.先将木棒长度按从大到小排序,也就是说匹配每一根等长木棒时总是优先挑选长的.剪枝方案如下:1. 若第i-1根木棒在当前方案的匹配中没有用到并且length[i]==length[i-1],则第i根木棒也不可能用到:2.若已匹配成功cnt根等长木棒,而第cnt+1根匹配不成功,则要剪枝:3.若在匹配第cnt+1根木棒时,最长的那根木棒stick会第一个被选

POJ2653 Pick-up sticks(线段相交)

题目链接: http://poj.org/problem?id=2653 题目描述: Pick-up sticks Description Stan has n sticks of various length. He throws them one at a time on the floor in a random way. After finishing throwing, Stan tries to find the top sticks, that is these sticks su

【POJ】2653 Pick-up sticks(计算几何+暴力)

http://poj.org/problem?id=2653 我很好奇为什么这样$O(n^2)$的暴力能过.... 虽然说这是加了链表优化的,但是最坏不也是$O(n^2)$吗...(只能说数据太弱...) 然后本题裸的判线段相交和点在直线上...(看了网上的标程,不判端点的情况都能过我也是醉了...) #include <cstdio> #include <cstring> #include <cmath> #include <string> #includ

uva 307 Sticks(回溯剪枝)

uva 307 Sticks 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 origi

2015 CCPC D- Pick The Sticks(UESTC 1218) (01背包变形)

http://acm.uestc.edu.cn/#/problem/show/1218 既然二维dp表示不了,就加一维表示是否在边界放置,放置一个,两个.有一个trick就是如果只放一根,那么多长都可以. wa了好多次(囧) 开始因为l[i]/2会出现小数,没注意,把所有的长度都x2就可以解决. 又wa了n次因为没注意j-l[i]时没加判断,为什么不是RE呢!不开心... /********************************************* Memory: 1140 KB

HDU 5543 Pick The Sticks (01背包)

题意:输入t,表示t组样例, 输入n,len,表示物品的个数和容器长度.输入n行a,v表示没个物品的长度和价值.每个物品只要能有一半放在容器上就可以(为了平衡,如果是一个物品的话不论它有多长都可以放在这个容器上),不可以重叠,求这个容器可以放最大的价值是多少. 分析:dp[i][j][k]表示前i个物品中放入长度为j的容器中有k个物品在边缘的最大价值. #include <iostream> #include <cstdio> #include <cstring> #i

【贪心专题】HDU 1051 Wooden Sticks (切割木棍)

链接:click here~~ 题目大意: 给n根木棍的长度和重量.根据要求求出制作木棍的最短时间.建立第一个木棍需要1分钟,若是接着要制作的木棍重量和长度都比此木棍长就不需要建立的时间,若是没有,则再需要建立时间.求时间最小为多少. [解题思路] 对木棍的长度和重量进行排序,以长度为首要考虑(也可以先考虑重量). 于是,我们对排序后的数组进行多次扫描,在一次建立时间内完成的进行标记,直到木棍全部标记(设置一个外部变量来计数已扫描的元素的数量) 举个别人的例子,加深理解 5 4 9  5 2 2