POJ.1416 Shredding Company (DFS)

本文深入讲解深度优先搜索(DFS)算法的应用,通过具体题目“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("\n");
}
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\n");
            else {printf("%d ",ret);output();}
        }else printf("error\n");
    }
    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函数预处理,将读入的字符串转换成数字。然后就是注意对多解的判断。

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

内容概要:本文详细记录了对一个Android ARM64静态ELF文件中字符串加密机制的逆向分析过程。该ELF文件的所有字符串均被加密,无法通过常规strings命令或IDA直接识别。作者通过分析发现,加密字符串存储在.rodata段,其解密所需信息(包括密文地址、长度和16位密钥)保存在.data.rel.ro段的40字节描述符中。核心解密函数sub_10F408采用自反的双pass流密码算法,结合固定密钥KEY_TERM(由.data段24字节数据计算得出),实现字节级非线性、位置与长度相关的加密。文章还复现了完整的Python解密脚本,并揭示了该保护机制的本质为代码混淆而非强加密,最终成功批量解密全部956条字符串,暴露程序真实行为,如shell命令模板、设备标识篡改、网络重置等操作。此外,文中还提及未启用的自定义壳框架及其反dump设计。; 适合人群:具备逆向工程基础的安全研究人员、二进制分析人员及对ELF保护技术感兴趣的开发者。; 使用场景及目标:①学习ELF二进制中字符串加密的典型实现方式与逆向突破口;②掌握从结构识别、函数追踪到算法还原的完整逆向流程;③理解“绑定二进制”的完整性校验设计及其局限性;④实践编写IDAPython脚本自动化提取与解密敏感数据。; 阅读建议:此资源以实战案例驱动,不仅展示技术细节,更强调逆向思维与验证方法,建议读者结合IDA调试环境,逐步跟随文中步骤进行动态分析与算法验证,深入理解每一步的推理依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值