组合长度poj1011

最近用使开发的过程中出现了一个小问题,顺便记载一下原因和方法--组合长度

    c++的现实方法可以考参http://blog.csdn.net/lyy289065406/article/details/6647960

    解题路思:

    DFS+剪枝

 

    POJ2362的强化版,重点在于剪枝

 

    令InitLen为所求的最短原始棒长,maxlen为给定的棒子堆中最长的棒子,sumlen为这堆棒子的长度之和,那么InitLen必定在围范[maxlen,sumlen]中

 

    根据棒子的灵巧度(棒子越长,灵巧度越低) DFS前先对全部棒子降序排序

 

    剪枝:

    1、  由于全部原始棒子等长,那么必有sumlen%Initlen==0;

    2、  若能在[maxlen,sumlen-InitLen]找到最短的InitLen,该InitLen必也是[maxlen,sumlen]的最短;若不能在[maxlen,sumlen-InitLen]找到最短的InitLen,则必有InitLen=sumlen;

    3、  由于全部棒子已降序排序,在DFS时,若某根棒子不合适,则跳过其面后全部与它等长的棒子;

    4、  最主要的剪枝:对于某个目标InitLen,在每次构建新的长度为InitLen的原始棒时,检查新棒的第一根stick[i],若在搜索完全部stick[]后都法无组合,则说明stick[i]法无在后以组合方法下组合,不必往下搜索(往下搜索会令stick[i]被舍弃),直接返回上一层

 

 import java.io.BufferedReader;

 import java.io.InputStreamReader;

 import java.util.Arrays;

 import java.util.StringTokenizer;

 public class Main {

     static boolean[] used;//用于记载组适时木棒的用使情况

     static int len;//截断后,木棒的根数

     static int[] s;//用来存储截断后木棒的长度

     static int sum;//全部木棒的总长度

     static int max;//木棒的大最长度

     static int parts;//理论上某种组合方法的木棒的根数

     public static void main(String[] args) throws Exception {

         BufferedReader read = new BufferedReader(new InputStreamReader(

                 System.in));

         

         //断判输入的木棒的根数否是为0.

         while ((len = Integer.parseInt(read.readLine()) ) != 0) {

            

       

    //根据截断后木棒的根数来建创一个整型组数

       

    s = new int[len];

             StringTokenizer take = new StringTokenizer(read.readLine());

             int index = 0;

             sum = 0;

             used = new boolean[len];

             

             //hasMoreTokens() .测试此 tokenizer 的字符串中否是还有更多的可用记标。

             while (take.hasMoreTokens()) {

           

 

           

    //nextToken().返回此 string tokenizer 的下一个记标。

           

    //将每一根木棒的长度存入s[]组数中

                 s[index] = Integer.parseInt(take.nextToken());

                 

                 //盘算木棒的总长度

                 sum += s[index++];

             }

             

             //sort(int[] a) .对指定的 int 型组数按数字升序停止排序。

             Arrays.sort(s);

             

             //取得截断后木棒的大最长度

             max = s[len - 1];

             

             

             /**

              * 

              */

             

             //在[max,sum]之间找寻initlen

             for (; max <= sum; max++) {

                 

           

    //如果总长度sum对max整除

           

    if (sum % max == 0) {

           

 

           

    //盘算以max为原始长度,这时候应该有多少根木棒

                     parts = sum / max;

                     

                     if (search(0, len - 1, 0)) {

                         System.out.println(max);

                         break;

                     }

                 }

             }

         }

     }

     /**

      * search(int res, int next, int cpl)主要用于找寻最短的原始棒长

      * 其主要思惟括包以下几点:

      * 1)首先断判后以的组合长度res否是经已足满后以的原始棒长的可能值max,

      * 如果足满了,将组合长度res置为0,next置为len-2,已组合的木棒根数cpl加1.

      * 

      * 2)断判已组合的木棒根数cpl否是和理论上要组合木棒根数parts致一,

      * 如果致一,这证明经已找到最短原始长度,返回true

      * 

      * 3)如果进入到这一步,则证明还没有组合现实,这是重新开始组合一根木棒

      * 1))首先断判否是还有棒子用于组合,如果没有,则执行接下来的false.

      * 如果有,断判该棒子否是经已被用使过,如果被用使过,则用使下一根棒子,

    每日一道理
流逝的日子像一片片凋零的枯叶与花瓣,渐去渐远的是青春的纯情与浪漫。不记得曾有多少雨飘在胸前风响在耳畔,只知道沧桑早已漫进了我的心爬上了我的脸。当一个人与追求同行,便坎坷是伴,磨难也是伴。

      * 如果没有被用使过,则断判组合长度res+该棒子的长度s[next]否是<=后以最短原始棒长的可能值max

      * 如果不成立,则证明将剩下的棒子的长度都加起来,如果······

      * 

      * 

      * 

      * @param res

      * @param next

      * @param cpl

      * @return

      */

     public static boolean search(int res, int next, int cpl) {

         

   

    /**

   

 * res:经已组合的长度

   

 * next:要组合的木棒

   

 * cpl:经已组合的木棒的根数

   

 */

   

 

   

    /**

   

 * 如果组合的长度经已到达木棒的大最长度

   

 * 则停止下一轮组合:

   

 * 组合长度res置0

   

 * 经已组合好的木棒根数cpl的值+1

   

 * 定确下一根要组合的木棒

   

 */

   

    if (res == max) {

             res = 0;

             next = len - 2;

             cpl++;

         }

         

   

    /**

   

 * 如果经已组合好顶峰木棒数与理论上的等相,则

   

 * 返回true

   

 */

         if (cpl == parts) {

             return true;

         }

         

         //从大到小开始组合

         while (next >= 0){

       

 

       

    //如果next对应的木棒还没有用使

             if (used[next] == false) {

           

 

           

    //如果后以组合长度小于木棒的大最长度

                 if (res + s[next] <= max){

               

 

               

    //将后以木棒的用使属性识标为true

                     used[next] = true;

                     

                     

                     /**

                      * 续继组合,如果下一轮组合刚刚好足满件条,则

                      * 返回true,组合现实

                      */

                     if (search(res + s[next], next - 1, cpl)) {

                         return true;

                     }

                     

                     /**

                      * 如果面上的if语句没有执行则证明,还没有组合现实

                      * 

                      */

                     

                     /**

                      * 如果执行到这里,则证明,后以木棒其实不合适用于组合

                      * 将后以经已用使到的木棒的用使属性记为false

                      */

                     used[next] = false;

                     

                     /**

                      * 对于新棒的第一根棒子如果在搜索万所搜棒子后以都法无组合

                      * ,则证明该棒子在后以组合方法下法无组合

                      *所以,直接返回上一层 

                      */

                     if (res == 0) {

                         break;

                     }

                     

                     

                     if (res + s[next] == max) {

                         break;

                     }

                 }

                 

                 /**

                  *如果后以组合长度加上接下来的那一根木棒的长度大于大最长度

                  *,或者 经已现实这一次的组合,却还没有到达大最大最长度

                  */

                 

                 

                 int i = next - 1;

                 

                 /**

                  * while循环主要表现剪枝法:

                  * 如果后以木棒的长度不合适,那么

                  * 接下来的和后以木棒长度同相的木棒也不合适

                  * 

                  */

                 while (i >= 0 && s[i] == s[next]) {

                     i--;

                 }

                 next = i;

                 

                 

                 /**

                  * for循环的主要逻辑:

                  * 遍历接下来的剩下的全部木棒,

                  * 盘算剩下全部木棒的总长度l_s

                  */

                 int l_s = 0;

                 for (int j = next; j >= 0; j--) {

                     if (!used[j]) {

                         l_s += s[j];

                     }

                 }

                 

                 /**

                  * if循环的主要逻辑:

                  * 如果际实剩下全部木棒的总长度l_s<

                  * 还需要的木棒的长度,则,跳出循环

                  * 证明

                  */

                 if (l_s < max - res) {

                     break;

                 }

                 

                 /**

                  * 剩下的木棒的总长度>还需要的木棒的长度,则

                  * 续继组装

                  */

                 continue;

             }

             

             //如果后以的木棒经已被用使过,将下标   - 1

             next--;

         }

         

         //如果遍历完全部的木棒都没有组合功成,则

         //返回false.

         return false;

     } 

    }

文章结束给大家分享下程序员的一些笑话语录: 腾讯的动作好快,2010年3月5日19时28分58秒,QQ同时在线人数1亿!刚刚看到编辑发布的文章,相差才2分钟,然后连专题页面都做出来了,他们早就预料到了吧?(其实,每人赠送10Q币,轻轻松松上两亿!)

posted @ 2013-04-21 10:37  xinyuyuanm  阅读(160)  评论(0编辑  收藏  举报