• POJ.1416 Shredding Company (DFS)


    POJ.1416 Shredding Company [从零开始DFS(8)]

    点我挑战题目

    从零开始DFS
    HDOJ.1342 Lotto [从零开始DFS(0)] — DFS思想与框架/双重DFS
    HDOJ.1010 Tempter of the Bone [从零开始DFS(1)] —DFS四向搜索/奇偶剪枝
    HDOJ(HDU).1015 Safecracker [从零开始DFS(2)] —DFS四向搜索变种
    HDOJ(HDU).1016 Prime Ring Problem (DFS) [从零开始DFS(3)] —小结:做DFS题目的关注点
    HDOJ(HDU).1035 Robot Motion [从零开始DFS(4)]—DFS题目练习
    HDOJ(HDU).1241 Oil Deposits(DFS) [从零开始DFS(5)] —DFS八向搜索/双重for循环遍历
    HDOJ(HDU).1258 Sum It Up (DFS) [从零开始DFS(6)] —DFS双重搜索/去重技巧
    HDOJ(HDU).1045 Fire Net [从零开始DFS(7)]—DFS练习/check函数的思想
    POJ.1416 Shredding Company [从零开始DFS(8)]—DFS练习/sum函数的设计

    题意分析

    给出一个目标数字n和一串数字序列s,要求切割序列s为若干数字段s1,s2,s3……sn,最后求出最大的 不超过目标数字n的 序列s切割方式,和这些字段的和。若对于最大的数字有多种切割方式,则输出rejected;若没有这样的切割方式,则输出error。

    直接对给出的数字串操作有些不方便,我们不妨想想挡板法。对于给出的序列s(若其有x位),则有x-1个空挡。对于每一个空挡,我们有选/不选两种选择,这又回到了讨论过的那种选/不选的模型,可以用dfs暴力枚举来解决此类问题。

    题目要求输出这样的分割方式和最大的和,则在dfs函数中一定有更新最大和的部分,并且还要保存这样的分割方式。递归边界就是,如果分割完了,那么就计算一下当前的和,如果和比目前的最大和大并且比目标值小,就更新,否则就舍弃。

    分析到这里其实就差不多了,我在做此题时比较伤脑筋的是如何计算这样这样字段的和,还有如何保存起来。想到的解决办法是:
    1.用一个数组gap来表示间隔。对于数字序列num[1]num[2]……num[n](num[i]表示的是一位数字),gap[i]表示num[i]和num[i+1]中是否有间隔。若有则为1,否则为0;
    2.为便于计算字段和,规定gap[0] = gap[n] = 1(n为给出的字符序列的长度,如12345的长度为5);
    3.用save数组表示当前最优的分割方式。

    上代码。

    代码总览

    /*
        Title:POJ.1416
        Author:pengwill
        Date:2017-2-14
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    char nu[100];
    int num[100],gap[100],save[100];
    int ret,len,test,time= 0;
    long long tar;
    bool mult = false, judge = false;
    void init()
    {
        memset(gap,0,sizeof(gap));
        len = strlen(nu);
        for(int i = 0,j = 1; i<len;++i,++j) num[j] = nu[i]-'0';
        judge = mult  = false;
        ret = 0;gap[0] = gap[len] = 1; test = 0;time = 0;
    }
    int sum()
    {
        int base = 1; int ans = 0; int t = 0;
        for(int i = len ; i>=0; --i){
            if(gap[i] == 0){
                base*=10;
                t += num[i] * base;
            }else if(gap[i] == 1){
                ans+=t; base = 1;
                t = num[i] * base;
            }
        }
        return ans;
    }
    void cpy()
    {
        for(int i = 0; i<=len ;++i) save[i] = gap[i];
    }
    // gap[i] (1<=gap<=len)
    // gap[i] = 0 -> not chose;
    // gap[i] = 1 -> chose;
    void output()
    {
        for(int i = 1;i<=len;++i){
            printf("%d",num[i]);
            if(i!=len){
                if(save[i] == 1) printf(" ");
            }
        }
        printf("
    ");
    }
    void dfs(int depth,int tag)
    {
        if(len==depth){
            int t = sum();
            if(t>ret && t<=tar){
                judge = true;
                time = 1;
                cpy();
                ret = t;
            }else if(t==ret && t<=tar){
                time++;
            }
            return;
        }
        gap[depth] = tag;
        if(depth == len-1){
            dfs(depth+1,1);//chose gap
        }else{
            dfs(depth+1,1);//chose gap
            dfs(depth+1,0);//don't chose gap
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%lld %s",&tar,nu) && tar){
            init();
            dfs(0,1);
            if(judge){
                if(time>1) printf("rejected
    ");
                else {printf("%d ",ret);output();}
            }else printf("error
    ");
        }
        return 0;
    }

    比较难设计的就是sum函数。

    int sum()
    {
        int base = 1; int ans = 0; int t = 0;
        for(int i = len ; i>=0; --i){
            if(gap[i] == 0){
                base*=10;
                t += num[i] * base;
            }else if(gap[i] == 1){
                ans+=t; base = 1;
                t = num[i] * base;
            }
        }
        return ans;
    }

    sum 函数是从右向左计算的,大致思路为:
    1.如果gap[i] = 1, 则将t累加到ans上,重置base和t;
    2.如果gap[i] = 0,则base自乘10,然后和num[i]相乘累加到t上。
    自由向左,相当于模拟的从低位到高位,算起来比较自然。cpy函数完成对最优解的拷贝。inti函数预处理,将读入的字符串转换成数字。然后就是注意对多解的判断。

    桃李春风一杯酒,江湖夜雨十年灯。

  • 相关阅读:
    Js判断是否改动
    导入用户数据到Discuz! X3.2 并实现同步登陆
    win2003(sp2 x86)+iis6+php-5.3.5-Win32 配置
    bblittle.com
    Macbook Hbase(1.2.6) 伪分布式安装,Hadoop(2.8.2) ,使用自带zookeeper
    LeetCode 696. Count Binary Substrings
    LeetCode 637. Average of Levels in Binary Tree
    LeetCode 226. Invert Binary Tree
    LeetCode 669. Trim a Binary Search Tree
    LeetCode 575. Distribute Candies
  • 原文地址:https://www.cnblogs.com/pengwill/p/7367166.html
Copyright © 2020-2023  润新知