题意:给你一个n,还有一张卡片m 求出分割成离x个数累加起不能大于n 而且要n-(x1+x2....xn)要最小
例如:50 12346
n=50,m=12346
就可以分割为(1,23,4,6)= 34,(1,2,34,6)=43
如果 分割成最小的数都大于n的话输出error
如果分割最小值有重复则输出rejected
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#define maxn 1000000
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int mx,mxpath;//mx=最小的距离差,mxpath则是记录的最小的path
int n;
int path;//1121 等于 1 2 34 6 连续的个数 方便记录
int cnt[maxn];//记录该数出现的个数
int toInt(char* s,int len)//将s到s+len转换成int数
{
int res=0;
for(int i=0;i<len;i++)
{
res=(res<<1)+(res<<3)+s[i]-48;//=res*10+s[i]-48
}
return res;
}
//str 表示当前处理状态的字符串 len记录的是str的长度 sum记录的是分割的和
void dfs(char *str,int len,int sum)
{
if(len==0)
{
cnt[sum]++;
if(n-sum<mx)
{
mx=n-sum;
mxpath=path;
}
return;
}
for(int i=1;i<=len;i++)//连续的i长度
{
int a=toInt(str,i);
if(sum+a>n)//如果在i个长度就大于了n那么没有继续循环下去必要因为下次i+1状态 a会乘以十比当前的的值还要大
{
break;
}
path=(path<<1)+(path<<3)+i;//记录连续的次数
dfs(str+i,len-i,sum+a);//str+i 表示连续了i个长度,不需要在去前面处理方便后面迭代处理
path/=10;//回溯回来删除i
}
}
int main()
{
char cmd[10];
while(~scanf("%d%s",&n,cmd)){
if(n==0)
{
break;
}
int len = strlen(cmd);
int sum=toInt(cmd,len);
int sum1=0;
for(int i=0;i<len;i++)
{
sum1+=cmd[i]-48;
}
if(n==sum){//如果n就等于m不分割的数那么直接输出
printf("%d %d\n",n,n);
continue;
}
if(n>=sum||sum1>n){
printf("error\n");
continue;
}
mx=sum;
path=0;
mxpath=0;
mem(cnt,0);
dfs(cmd,len,0);
if(cnt[n-mx]!=1){
printf("rejected\n");
}else{
path=0;
//求出来的mxpath恰好是反的 将path 进行一个翻转
while(mxpath!=0)
{
path=(path<<1)+(path<<3)+mxpath%10;
mxpath/=10;
}
printf("%d ",n-mx);
char* str=cmd;
while(path!=0)
{
int len=path%10;
printf("%d ",toInt(str,len));
path/=10;
str+=len;
}
printf("\n");
}
}
}