dfs貌似不剪枝也能过 数据水水的 不过练练剪枝拓一下思路
每组两个数t num 输入0 0结束
分割数字num为任意组 让这几组加和最接近t(且<=t) 无解输出error 多解输出rejected 否则输出加和还有分割情况
做搜索剪枝有点小经验 搜索的时候逆向搜索 求最大就从大往小搜 求最小就从小往大搜 这样一出现不足(求最大时)或溢出(求最小) 立即return 即可实现高效剪枝 因为此时后继情况均比当前小(大)(为其枝叶)
此题还有点坑是rejected情况 如果出现多种最大分割 或最大分割中某组前导为0(0可单独扣出作为一组) 即为rejected
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int num[7],tmp[7],len,mm,t,f;//num-分割方式 tmp-临时分割 len-分割组数 mm-最大分割和 f-判多解(rejected)
int getlen(int x)//求x位数对应的10^n 用以dfs时取余(分割)
{
int cnt = 1;
while(x)
{
x /= 10;
cnt *= 10;
}
return cnt/10;
}
void dfs(int rest,int sum,int site,int l,int p)//p 0无前导零 1有前导
{
if(sum + rest <= t && sum + rest >= mm)
{
if(sum + rest == mm || p == 1)//满足条件时多解或某组有前导零
{
f = 1;
mm = sum + rest;
return;
}
f = 0;
mm = sum + rest;
memcpy(num,tmp,sizeof(tmp));
num[site++] = rest;
len = site;
return;
}
if(sum + rest < t && sum + rest < mm) return;//当前已小 后继更小
for(int i = l; i >= 1; i /= 10)
{
tmp[site] = rest/i;
if(i > 10 && rest%i/(i/10) == 0) dfs(rest%i, sum + rest/i, site+1, i/100,1);//判分割后余下的数是否有前导零
else dfs(rest%i, sum + rest/i, site+1, i/10,p);
}
}
int main()
{
int n;
while(~scanf("%d %d",&t,&n) && (t+n))
{
f = 0;
len = 0;
mm = -1;
dfs(n,0,0,getlen(n),0);
if(mm == -1) puts("error");
else if(f) puts("rejected");
else
{
printf("%d",mm);
for(int i = 0; i < len; ++i) printf(" %d",num[i]);
puts("");
}
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-10 09:44:49