POJ1416 切纸片

本文探讨了一个特定的算法问题,即如何将一个数字序列分割成若干个数,使得这些数的总和接近但不超过给定的目标值,同时最小化目标值与实际总和之间的差距。通过递归深度优先搜索的方法,文章详细解释了算法的实现过程,包括如何通过预处理将数字序列转换为整数,以及如何在遍历过程中更新最佳解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 题意:给你一个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");
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值