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;
}