1 条题解

  • 0
    @ 2025-4-7 15:00:51

    题意:

    公司现在要发明一种新的碎纸机,要求新的碎纸机能够把纸条上的数字切成最接近而不超过targettarget值。比如,targettarget的值是5050,而纸条上的数字是1234612346,应该把数字切成四部分,分别是1122343466。因为这样所得到的和4343 (=1+2+34+6)(= 1 + 2 + 34 + 6) 是所有可能中最接近而不超过5050的。(比如11, 2323, 44, 和66 就不可以,因为它们的和不如4343接近5050,而1212, 3434, 66也不可以,因为它们的和超过5050了。碎纸还有以下三个要求:

    1、如果targettarget的值等于纸条上的值,则不能切。 2、如果没有办法把纸条上的数字切成小于targettarget,则输出errorerror。如targettarget11而纸条上的数字是123123,则无论你如何切得到的和都比11大。 3、如果有超过一种以上的切法得到最佳值,则输出rejectedrejected。如targettarget1515,纸条上的数字是111111,则有以下两种切法111111或者111111。 你的任务是编写程序对数字进行划分以达到最佳值。

    解题思路:

    DFSDFS

    (1)(1)比如一个66位数nn,切成为66个数的话,这66个数的和如果大于目标数targettarget则不用再搜索了,因为这肯定是所有划分中和最小的,而最小都比目标数大,自然就没有合要求的答案了。 (2)(2) 如何切分,假如以5050 1234612346 为例。 第一步,先切下一个"11",然后递归去切"23462346"; 第二步,再切下一个"1212",然后递归去切"346346"; 第三步,再切下一个"123123",然后递归去切"4646"; 第四步,再切下一个"12341234" 然后递归去切"66" 第五步,再切下"1234612346"。

    (3)(3)切下来的 前面的数字串部分 则加入到划分的和,剩下的部分继续递归,直到已经划分出来的数字长度lenlen等于数字串总长度strlen(num)strlen(num)。为了记录划分方式,使用intint数组devidedevide记录每一次划分的长度,比如样例5050 1234612346划分为4343 11 22 3434 66,那devide[0]=1devide[0] = 1,devide[1]=1devide[1] = 1,devide[2]=2devide[2] = 2,devide[3]=1devide[3] = 1。而且为了保存最优解,需要在已经划分出来的数字长度lenlen等于数字串总长度strlen(num)strlen(num),并且abs(bestxtarget)>abs(sumtarget)abs(bestx-target)>abs(sum-target)时,更新最优解bestx=sumbestx = sum,并且将devidedevide转存到ansdevideansdevide中,为了方便之后答案的输出。

    (4)(4)使用字符数组存储数字串numnum,这样在搜索时,只要控制字符数组的起止位置就可以模拟数字串的拆分。

    (5)(5)剪枝方法:在搜索时若发现部分和 大于(不能等于)targettarget时,则可结束搜索。

    在进入dfsdfs搜索时,可以把特殊情况排除

    1)errorerror的判定要在搜索前进行

    2)当数字串numnumtargettarget相等时,直接输出,不用划分

    3)当数字串的每一位数字之和sum2sum2等于targettarget时,直接逐位输出,每个数字为一个划分

    注意这种情况有一个特例,就是00出现的时候,

    例如样例:66 11041104

    它的最优划分有两种 66 11 11 00 44

    66 11 11 0404

    所以此样例应该输出rejectedrejected

    所以这种情况下,应该保证数字串numnum中没有00,才可以直接逐位输出

    (6)rejected(6)rejected(多个最优解)的判定要在搜索后判定。当最优解出现两次的时候(出现abs(bestxtarget)==abs(sumtarget)abs(bestx-target)==abs(sum-target)),使用全局变量CountCount计数。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int target;
    char num[10];
    int bestx;
    int Count;
    int anslen;
    int ansdevide[10];
    void dfs(char *ch,int len,int sum,int c,int *devide)
    {///len为当前已经划分的数字串的长度,sum为当前已划分的数字的总和
    ///c为划分的数字的块数
        if(len == strlen(num))
        {
            if(abs(bestx-target)>abs(sum-target))
            {
                Count=0;
                anslen = c;
                bestx = sum;
                for(int i=0;i<c;i++)
                    ansdevide[i] = devide[i];
                return;
            }
            if(abs(bestx-target)==abs(sum-target))///出现多个最优解
            {
                Count++;
            }
            return;
        }
        for(int i=1;i<=strlen(ch);i++)
        {///确定下一步划分的长度i
            int newsum = 0;
            for(int j=0;j<i;j++)
                newsum = newsum*10 + (ch[j]-'0');
            newsum+=sum;
            devide[c] = i;
            if(newsum<=target)
                dfs(ch+i,len+i,newsum,c+1,devide);
        }
    }
    
    int main()
    {
        while(cin>>target && target)
        {
            cin>>num;
            int sum1 = 0;///计算纸上的数是多少
            int sum2 = 0;///每一位的和
            for(int i=0;i<strlen(num);i++)
            {
                sum1 = sum1*10+(num[i]-'0');
                sum2 += num[i]-'0';
            }
            if(sum1 == target)
                cout<<target<<" "<<target<<endl;
            else if(sum2 > target)
            {
                cout<<"error"<<endl;
            }
            else if(sum2 == target && !strchr(num,'0'))
            {
                cout<<target;
                for(int i=0;i<strlen(num);i++)
                {
                    cout<<" "<<num[i];
                }
                cout<<endl;
            }else
            {
                Count = 0;
                bestx = 0;
                int devide[10];
                dfs(num,0,0,0,devide);
                if(Count > 0)
                    cout<<"rejected"<<endl;
                else{
                    cout<<bestx;
                    int temp=0;
                    for(int i=0;i<anslen;i++)
                    {
                        cout<<" ";
                        for(int j=temp;j<temp+ansdevide[i];j++)
                        {
                            cout<<num[j];
                        }
                        temp += ansdevide[i];
                    }
                    cout<<endl;
                }
            }
    
        }
        return 0;
    }
    
    • 1

    信息

    ID
    417
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者