POJ 1416 && HDU 1539 Shredding Company(dfs)

本文介绍了一种算法,用于将数字串中的数字切成多个部分,使得这些部分的和尽可能接近但不超过目标值。该算法考虑了特定的限制条件,并提供了有效解决方案。

Description
公司现在要发明一种新的碎纸机,要求新的碎纸机能够把纸条上的数字切成最接近而不超过target值。比如,target的值是50,而纸条上的数字是12346,应该把数字切成四部分,分别是1,2,34,6。因为这样所得到的和43(=1+2+34+6) 是所有可能中最接近而不超过50的。(比如1,23,4和6 就不可以,因为它们的和不如43接近50,而12, 34, 6也不可以,因为它们的和超过50了)。碎纸还有以下三个要求:
1、如果target的值等于纸条上的值,则不能切。
2、如果没有办法把纸条上的数字切成小于target,则输出error。如target是1而纸条上的数字是123,则无论你如何切得到的和都比1大。
3、如果有超过一种以上的切法得到最佳值,则输出rejected。如target为15,纸条上的数字是111,则有以下两种切法11、1或者1、11.
你的任务是编写程序对数字进行划分以达到最佳值
Input
多组输入,每组用例占一行,包括两个整数target和n分别表示碎纸机的target值和纸条上的值
Output
对于每组用例,若不能且或者无法满足条件则输出error,若能切且只有一种切法则输出对应切法,若有多种切法则输出rejected
Sample Input
50 12346
376 144139
927438 927438
18 3312
9 3142
25 1299
111 33333
103 862150
6 1104
0 0
Sample Output
43 1 2 34 6
283 144 139
927438 927438
18 3 3 12
error
21 1 2 9 9
rejected
103 86 2 15 0
rejected
Solution
dfs
这道题其实就是在一个数字串中加空格,所以开一个mark数组标记每一位前是否要加空格,搜索的时候对每一位都有两种情况,即将该位归于上一段和将该位归于新的一段,分别向下搜索两次即可,注意标记和回溯
Code

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,ans,flag,len,bit[11];
bool Mark[22],mark[22];
void dfs(int pos,int sum,int num)
{
    if(sum+num>n)//不满足条件 
        return ;
    if(pos==len)//已经切完 
    {
        sum+=num;
        if(sum<=n&&sum>ans)//更新答案 
        {
            ans=sum;
            flag=false;
            for(int i=0;i<len;i++)
                Mark[i]=mark[i];
            return ;
        }
        if(sum==ans)//多组解 
            flag=true;
        return ;
    }
    dfs(pos+1,sum,num*10+bit[pos]);//将pos位归到这一段 
    mark[pos]=true;//标记 
    dfs(pos+1,sum+num,bit[pos]);//将pos位归到下一段 
    mark[pos]=false;//回溯 
}
int main()
{
    while(scanf("%d%d",&n,&m),n||m)
    {
        flag=len=ans=0;
        memset(mark,false,sizeof(mark));//记录每一位前是否要加空格 
        int temp[11];
        while(m)//将数字转化为字符串处理 
        {
            temp[len++]=m%10;
            m/=10;  
        } 
        for(int i=0;i<len;i++)
            bit[len-i-1]=temp[i];
        dfs(1,0,bit[0]);
        if(!ans)//无解 
            printf("error\n");
        else if(flag)//多组解 
            printf("rejected\n");
        else//唯一解 
        {
            printf("%d ",ans);
            for(int i=0;i<len;i++)
            {
                if(Mark[i])//判断每一位前是否要加空格 
                    printf(" ");
                printf("%d",bit[i]);                
            }
            printf("\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值