zoukankan      html  css  js  c++  java
  • 组合长度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币,轻轻松松上两亿!)

  • 相关阅读:
    【143】360云盘资源
    【142】阿蛮歌霸使用技巧
    [置顶] 程序员必知(三):一分钟知道URI编码(encodeURI)
    [置顶] Oracle job procedure 存储过程定时任务
    浅析动态表单
    DoctorNote医生处方笔记开发记录
    Step2:配置Oracle Dataguard
    IOS开发UIImage中stretchableImageWithLeftCapWidth方法的解释
    解析客户端脚本、服务器端脚本
    tomcat目录结构
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3033581.html
Copyright © 2011-2022 走看看