POJ 1011 Sticks
2014-04-22 21:41
525 查看
题目大意:
乔治将几根长度一样的木棍随机砍断,得到若干长度随机的小木棍,现在他想把这些小木棍拼回去,但是已经忘记掉原木棍的长度和根数,现在请你编程确定原木棍最短为多少。
现有多个测例,每个测例都给出随机长度小木棍的数量n(n不超过64),并给出每根小木棍的长度(小木棍超度不超过50),要求输出可能的原木棍的最小长度,以n = 0作为输入的结束。
题目链接
注释代码:
无注释代码:
优化:
注释代码:
randomly:adv, 随机地,任意地
乔治将几根长度一样的木棍随机砍断,得到若干长度随机的小木棍,现在他想把这些小木棍拼回去,但是已经忘记掉原木棍的长度和根数,现在请你编程确定原木棍最短为多少。
现有多个测例,每个测例都给出随机长度小木棍的数量n(n不超过64),并给出每根小木棍的长度(小木棍超度不超过50),要求输出可能的原木棍的最小长度,以n = 0作为输入的结束。
题目链接
注释代码:
/* * Problem ID : POJ 1011 Sticks * Author : Lirx.t.Una * Language : GCC * Run Time : 0 ms * Run Memory : 360 KB */ #pragma GCC optimize("O2") #include <string.h> #include <stdlib.h> #include <stdio.h> #define TRUE 1 #define FALSE 0 //maximum number of sticks //木棍的最大数量 #define MAXSTKN 64 typedef char BOOL; short len[MAXSTKN];//每条木棍的长度,从下标0计 BOOL usd[MAXSTKN];//used,表示第i号棍子是否使用过 int fcmp(const void *a, const void *b) { return *(short *)b - *(short *)a; } //思路:由于每一个目标段中都至少包含一条小木棍 //因此目标段的最小长度至少为小木棍的最大长度 //因此可以先将小木棍按照长度从大到小排序 //然后在贪心选择的基础上DFS BOOL dfs( int ncplt, short cl, int cur, int ns, short sl, int n ) { //completed number,已经拼好的棍子的数量 //current length,目前已经拼凑了多长(是指一个段里) //current stick,当前正扫描的木棍的编号 //segment number,目标段的个数 //segment length,目标段的长度 //totol stick number,小木棍的总数量 if ( ncplt == ns )//如果已经拼完所有目标段则成功退出 return TRUE; for ( ; cur < n; cur++ ) {//否则就从当前木棍开始检查 //!!!剪枝1 //如果当前木棍已被使用过了 //或者是和已经拼好的长度相加超过目标段长 //则直接跳过 if ( usd[cur] || cl + len[cur] > sl ) continue; //否则就可以标记为使用过 usd[cur] = TRUE; //否则就可以标记为使用过,接下来做相应的检查 //否则就可以标记为使用过,接下来做相应的检查 if ( cl + len[cur] == sl ) { //则继续搜索 //此时因为cl和len[cur]已经拼好了一个完整的段 //因此进入下一层搜索时拼好的数量就是ncplt+1了 //并且拼好的长度清零 //并且从头开始扫描 if ( dfs( ncplt + 1, 0, 0, ns, sl, n ) ) return TRUE; //!!!剪枝2 //如果剩下的所有小木棍无法完成目标 //则表示当前方案失败 //因为若不使用len[cur],但是为了完成目标 //接下来必定要找到能和cl组成完整段的小木棍 //即使能找到,那这些和cl组成完整段的小木棍的效果 //和len[cur]是一样的,所以就算这一层中不适用len[cur] //后面的搜索同样是不成功的 //因此这里需要剪枝,不能往下搜索了 return usd[cur] = FALSE; } //接下来就是cl + len[cur] < sl的情况了 //继续下一层搜索,只不过拼好的长度为cl + len[cur]了 //由于当前还没有拼完一段目标段,因此还是ncplt //并且得从cur + 1的位置继续扫描 //因为len是从大到小排序过的(方便贪心选择) if ( dfs( ncplt, cl + len[cur], cur + 1, ns, sl, n ) ) return TRUE; //如果不成功,则有可能替换len[cur] usd[cur] = FALSE; //!!!剪枝3 //如果cl = 0,则表示拿len[cur]和其它剩下的木棍凑,凑不出目标 //因此只能失败退出 if ( !cl ) return FALSE; //!!!剪枝4 //否则就表示cl和len[cur]组合在一起是不能和剩下的小木棍凑出目标 //这就意味着cl和其它len组合可能凑出目标 //因此尝试换其它len和cl组合 //但是得避免后面重复测试和len[cur]一样长的木棍 while ( cur + 1 < n && len[cur] == len[cur + 1] ) cur++; } return FALSE;//所有小木棍都检测完仍然凑不出 } int main() { int n;//木棍数量 short tl;//totol length,小木棍总长 short ns;//number of segment,目标段数量 short sl;//length of segment,目标段长度(sl = tl / ns) BOOL cd;//can be done,用于标志当前sl能否被成功凑出 int i; while ( scanf("%d", &n), n ) { for ( tl = 0, i = 0; i < n; i++ ) { scanf("%d", len + i); tl += len[i]; } qsort(len, n, sizeof(short), &fcmp); cd = FALSE;//初始化 //!!!剪枝5 //不用sl从len[0]一直++到tl的方式进行搜索 //因为最多只能被分为tl / len[0]段,最少分为1段 //用段数来扫描比直接用段长++扫描的方式少很多判( tl % sl ) == 0的环节 for ( ns = tl / *len; ns >= 2; ns-- )//!!!剪枝6,如果ns = 2也不行,则ns = 1是必然成立的 //因此不用麻烦地对ns = 1也进行搜索了!!! if ( !( tl % ns ) ) { memset(usd, FALSE, sizeof(usd)); if ( dfs( 0, 0, 0, ns, sl = tl / ns, n ) ) { cd = TRUE; break; } } if ( cd ) printf("%d\n", sl); else printf("%d\n", tl); } return 0; }
无注释代码:
#pragma GCC optimize("O2") #include <string.h> #include <stdlib.h> #include <stdio.h> #define TRUE 1 #define FALSE 0 #define MAXSTKN 64 typedef char BOOL; short len[MAXSTKN]; BOOL usd[MAXSTKN]; int fcmp(const void *a, const void *b) { return *(short *)b - *(short *)a; } BOOL dfs( int ncplt, short cl, int cur, int ns, short sl, int n ) { if ( ncplt == ns ) return TRUE; for ( ; cur < n; cur++ ) { if ( usd[cur] || cl + len[cur] > sl ) continue; usd[cur] = TRUE; if ( cl + len[cur] == sl ) { if ( dfs( ncplt + 1, 0, 0, ns, sl, n ) ) return TRUE; return usd[cur] = FALSE; } if ( dfs( ncplt, cl + len[cur], cur + 1, ns, sl, n ) ) return TRUE; usd[cur] = FALSE; if ( !cl ) return FALSE; while ( cur + 1 < n && len[cur] == len[cur + 1] ) cur++; } return FALSE; } int main() { int n; short tl; short ns; short sl; BOOL cd; int i; while ( scanf("%d", &n), n ) { for ( tl = 0, i = 0; i < n; i++ ) { scanf("%d", len + i); tl += len[i]; } qsort(len, n, sizeof(short), &fcmp); cd = FALSE; for ( ns = tl / *len; ns >= 2; ns-- ) if ( !( tl % ns ) ) { memset(usd, FALSE, sizeof(usd)); if ( dfs( 0, 0, 0, ns, sl = tl / ns, n ) ) { cd = TRUE; break; } } if ( cd ) printf("%d\n", sl); else printf("%d\n", tl); } return 0; }
优化:
注释代码:
/* * Problem ID : POJ 1011 Sticks * Author : Lirx.t.Una * Language : C++ * Run Time : 0 ms * Run Memory : 136 KB */ #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define MAXN 64 using namespace std; char len[MAXN]; bool usd[MAXN]; int n;//小棍个数 int len_seg;//length of each segment,目标段长度 bool dfs( int n_rst, int seg_len_rst, int cur_i ) { //number of rest sticks,剩下没有拼完的小棍数 //rest segment length,目标段还有多少没被拼完 //current ith sticks,当前检测到第cur_i号小棍(下标从0开始) if ( !n_rst && !seg_len_rst ) return true;//全部拼完 if ( !seg_len_rst ) {//小棍没用完,但是当前目标段为0 //表示刚拼完一个目标段,还需用剩下的小棍拼目标端 seg_len_rst = len_seg;//初始化当前目标段待拼的剩余长度 cur_i = 0;//按照目标端从左到右小棍长度降低的规则从头开始检测小棍 } for ( ; cur_i < n; cur_i++ ) if ( !usd[cur_i] && len[cur_i] <= seg_len_rst ) {//检测的小棍不能大于当前剩余目标段长 usd[cur_i] = true;//符合要求,先试探性使用一下该小棍 //目标段中小棍从左到右长度递减 //因此一下次搜索cur_i必须前进一格 if ( dfs( n_rst - 1, seg_len_rst - len[cur_i], cur_i + 1 ) ) return true; usd[cur_i] = false;//搜索失败,退还该木棍 //剪枝1 //如果当前小木棍是当前 //如果当前小木棍是当前 //目标段的头 //目标段的尾 //则表示是上一次检测的小木棍有问题,不用继续替换当前小木棍,因此直接失败退出 if ( seg_len_rst == len_seg || seg_len_rst == len[cur_i] ) return false; //剪枝2 //剪枝3 //虽然当前小木棍既不是当前目标段的头也不是尾 //但反正是失败了,因此在接下来的搜索中排除和它一样长的小木棍 while ( cur_i + 1 < n && len[cur_i] == len[cur_i + 1] ) cur_i++; } //剪枝4 return false;//一直都没搜出答案,失败退出 } bool fcmp( char a, char b ) { return a > b; } int main() { int len_tot;//所有小棍总长度 int n_seg;//假设的目标段的个数 int i; bool done; while ( scanf("%d", &n), n ) { len_tot = 0; for ( i = 0; i < n; i++ ) { scanf("%d", len + i); len_tot += len[i]; } sort(len, len + n, fcmp); done = false; for ( n_seg = len_tot / *len; n_seg > 1; n_seg-- ) if ( !( len_tot % n_seg ) ) { memset(usd, 0, sizeof(usd)); if ( dfs( n, len_seg = len_tot / n_seg, 0 ) ) { done = true; break; } } if ( done ) printf("%d\n", len_seg); else printf("%d\n", len_tot); } return 0; }无注释代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define MAXN 64 using namespace std; char len[MAXN]; bool usd[MAXN]; int n; int len_seg; bool dfs( int n_rst, int seg_len_rst, int cur_i ) { if ( !n_rst && !seg_len_rst ) return true; if ( !seg_len_rst ) { seg_len_rst = len_seg; cur_i = 0; } for ( ; cur_i < n; cur_i++ ) if ( !usd[cur_i] && len[cur_i] <= seg_len_rst ) { usd[cur_i] = true; if ( dfs( n_rst - 1, seg_len_rst - len[cur_i], cur_i + 1 ) ) return true; usd[cur_i] = false; if ( seg_len_rst == len_seg || seg_len_rst == len[cur_i] ) return false; while ( cur_i + 1 < n && len[cur_i] == len[cur_i + 1] ) cur_i++; } return false; } bool fcmp( char a, char b ) { return a > b; } int main() { int len_tot; int n_seg; int i; bool done; while ( scanf("%d", &n), n ) { len_tot = 0; for ( i = 0; i < n; i++ ) { scanf("%d", len + i); len_tot += len[i]; } sort(len, len + n, fcmp); done = false; for ( n_seg = len_tot / *len; n_seg > 1; n_seg-- ) if ( !( len_tot % n_seg ) ) { memset(usd, 0, sizeof(usd)); if ( dfs( n, len_seg = len_tot / n_seg, 0 ) ) { done = true; break; } } if ( done ) printf("%d\n", len_seg); else printf("%d\n", len_tot); } return 0; }单词解释:
randomly:adv, 随机地,任意地
相关文章推荐
- POJ 1011 Sticks(搜索剪枝)
- poj_1011 Sticks
- POJ 1011 Sticks
- poj 1011 Sticks (DFS+剪枝)
- poj 1011 Sticks 经典dfs+剪枝
- 【暴力搜索】[POJ 1011]Sticks
- POJ1011———Sticks
- poj 1011 Sticks
- POJ1011 Sticks
- [POJ 1011]Sticks(DFS剪枝)
- POJ 1011(Sticks)解题纠错
- poj 1011-sticks
- POJ 1011 Sticks【DFS】
- poj_1011_sticks(搜索+剪枝)
- POJ1011 HDU1455 UVA307 UVALive5522 Sticks题解
- POJ-1011 sticks 棍棒拼接
- poj 1011 Sticks
- Poj 1011-Sticks
- poj 1011 sticks...
- poj 1011 Sticks 减枝搜索