POJ 1011 Sticks

来源:互联网 发布:只有我知上海见面会 编辑:程序博客网 时间:2024/05/22 04:24

题目大意:

        乔治将几根长度一样的木棍随机砍断,得到若干长度随机的小木棍,现在他想把这些小木棍拼回去,但是已经忘记掉原木棍的长度和根数,现在请你编程确定原木棍最短为多少。

        现有多个测例,每个测例都给出随机长度小木棍的数量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>#defineTRUE1#defineFALSE0//maximum number of sticks//木棍的最大数量#defineMAXSTKN64typedefcharBOOL;shortlen[MAXSTKN];//每条木棍的长度,从下标0计BOOLusd[MAXSTKN];//used,表示第i号棍子是否使用过intfcmp(const void *a, const void *b) {return *(short *)b - *(short *)a;}//思路:由于每一个目标段中都至少包含一条小木棍//因此目标段的最小长度至少为小木棍的最大长度//因此可以先将小木棍按照长度从大到小排序//然后在贪心选择的基础上DFSBOOLdfs( 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;//所有小木棍都检测完仍然凑不出}intmain() {intn;//木棍数量shorttl;//totol length,小木棍总长shortns;//number of segment,目标段数量shortsl;//length of segment,目标段长度(sl = tl / ns) BOOLcd;//can be done,用于标志当前sl能否被成功凑出inti;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);elseprintf("%d\n", tl);}return 0;}

无注释代码:

#pragma GCC optimize("O2")#include <string.h>#include <stdlib.h>#include <stdio.h>#defineTRUE1#defineFALSE0#defineMAXSTKN64typedefcharBOOL;shortlen[MAXSTKN];BOOLusd[MAXSTKN];intfcmp(const void *a, const void *b) {return *(short *)b - *(short *)a;}BOOLdfs( 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;}intmain() {intn;shorttl;shortns;shortsl;BOOLcd;inti;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);elseprintf("%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>#defineMAXN64using namespace std;charlen[MAXN];boolusd[MAXN];intn;//小棍个数intlen_seg;//length of each segment,目标段长度booldfs( 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++;}                                    //剪枝4return false;//一直都没搜出答案,失败退出}boolfcmp( char a, char b ) {return a > b;}intmain() {intlen_tot;//所有小棍总长度intn_seg;//假设的目标段的个数inti;booldone;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>#defineMAXN64using namespace std;charlen[MAXN];boolusd[MAXN];intn;intlen_seg;booldfs( 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;}boolfcmp( char a, char b ) {return a > b;}intmain() {intlen_tot;intn_seg;inti;booldone;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, 随机地,任意地

0 0
原创粉丝点击