NOI OpenJudge 1805 碎纸机

描述
你现在负责设计一种新式的碎纸机。一般的碎纸机会把纸切成小片,变得难以阅读。而你设计的新式的碎纸机有以下的特点:

1.每次切割之前,先要给定碎纸机一个目标数,而且在每张被送入碎纸机的纸片上也需要包含一个数。
2.碎纸机切出的每个纸片上都包括一个数。
3.要求切出的每个纸片上的数的和要不大于目标数而且与目标数最接近。

举一个例子,如下图,假设目标数是50,输入纸片上的数是12346。碎纸机会把纸片切成4块,分别包含1,2,34和6。这样这些数的和是43 (= 1 + 2 + 34 + 6),这是所有的分割方式中,不超过50,而又最接近50的分割方式。又比如,分割成1,23,4和6是不正确的,因为这样的总和是34 (= 1 + 23 + 4 + 6),比刚才得到的结果43小。分割成12,34和6也是不正确的,因为这时的总和是52 (= 12 + 34 + 6),超过了50。

还有三个特别的规则:
1.如果目标数和输入纸片上的数相同,那么纸片不进行切割。
2.如果不论怎样切割,分割得到的纸片上数的和都大于目标数,那么打印机显示错误信息。
3.如果有多种不同的切割方式可以得到相同的最优结果。那么打印机显示拒绝服务信息。比如,如果目标数是15,输入纸片上的数是111,那么有两种不同的方式可以得到最优解,分别是切割成1和11或者切割成11和1,在这种情况下,打印机会显示拒绝服务信息。

为了设计这样的一个碎纸机,你需要先写一个简单的程序模拟这个打印机的工作。给定两个数,第一个是目标数,第二个是输入纸片上的数,你需要给出碎纸机对纸片的分割方式。
输入
输入包括多组数据,每一组包括一行。每行上包括两个正整数,分别表示目标数和输入纸片上的数。已知输入保证:两个数都不会以0开头,而且两个数至多都只包含6个数字。

输入的最后一行包括两个0,这行表示输入的结束。
输出
对每一组输入数据,输出相应的输出。有三种不同的输出结果:

sum part1 part2 …
rejected
error

第一种结果表示:
1.每一个partj是切割得到的纸片上的一个数。partj的顺序和输入纸片上原始数中数字出现的次序一致。
2.sum是切割得到的纸片上的数的和,也就是说:sum = part1 + part2 +…
第一种结果中相邻的两个数之间用一个空格隔开。

如果不论怎样切割,分割得到的纸片上数的和都大于目标数,那么打印“error”。
如果有多种不同的切割方式可以得到相同的最优结果,那么打印“rejected”。

题目好长….我稍微总结一下题意。
就是给你两个数,一个是目标数,一个是纸片数,你需要把纸片数切成好几部分,然后把它们加起来组成一个新数,如12345可以拆成(1+2+3+4+5)==15。
要求组成的新数要比目标数小,还要尽量大。

如果目标数和纸片数相同的话,直接输出他俩就完了,
如果切出来的能组成的尽量大的数有多种方案,puts(“rejected”);
如果能切出来符合条件的数,输出组成这个数的所有数字….

这个题,我们可以从简单到难来想。
首先如果目标数和纸片数相同的话,直接输出他俩就完了
然后
如果不论怎样切割,分割得到的纸片上数的和都大于目标数,那么打印“error”。,我们一开始将答案附成一个极小值(比如说-1),如果DFS完了,答案还是极小值,说明没有答案。

如果切出来的能组成的尽量大的数有多种方案,puts(“rejected”);先立个flag,我们在DFS的过程中是不断更新答案的,如果当前搜到的答案和之前更新的答案一样,将flag=1,如果搜到了新的答案,将flag=0,这样。当flag==1的时候,puts(“rejected”);

把以上三种情况排除,那么问题来了…我们要怎么切数?
我们可以把纸片数一位一位拆到数组里,当我们DFS的时候,记录一个参数,为当前搜到了纸片数的第几位,当最后一位已经搜过了的时候,我们就得到了一种切割方案,详情怎么切,见下↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

void dfs(int tot,int num,int cnt) 
{//这是DFS的拆数部分
    if(num>m)//m为要切的数的位数,tmp为切出来的每一部分的值,shu记录的是每一位的值
    {//hah为切出来的数的总和,cnt为切出来的数的数量
        int hah=0;
        for(int i=1;iprintf("%d ",tmp[i]),hah+=tmp[i];
        printf("%d\n",hah); 
        puts("");
    }
    int hah=0;
    for(int i=num;i<=m;i++)
    {
        hah*=10;//
        hah+=shu[i];//这两句很重要。
        tmp[cnt]=hah;
        dfs(tot+hah,i+1,cnt+1);//这里tot没卵用...
    }
}

上面的tmp数组,储存的就是切开的数的各个部分,我们要开一个ans1数组,当我们更新到更大的部分和的时候的时候,将ans1数组里的值全都赋成当前tmp数组里的值。

这个题就这么完了…

#include
#include
#include
using namespace std;
int n,m;
int shu[23333];
int tmp[23333];

bool flag1;
void clr()
{
    memset(shu,0,sizeof(shu));
    flag1=0;
}
int ans1[23333];
int ans;
int lenth;
void dfs(int tot,int num,int cnt)
{
    if(tot>n)
        return;
    if(num>m)
    {
        if(tot==ans)
        {
            flag1=1;
            return;
        }
        if(tot>ans)
        {
            flag1=0;
            ans=tot;
            for(int i=1;i1;
        }
        return;
    }

    int hah=0;
    for(int i=num;i<=m;i++)
    {
        hah*=10;
        hah+=shu[i];
        tmp[cnt]=hah;
        dfs(tot+hah,i+1,cnt+1);
    }
}
int main()
{
    while(1)
    {
        clr();
        string a;
        scanf("%d",&n);
        ans=-1;
        cin>>a;
        int hah=0;
        m=a.size();
        if(n==0)
        break; 
        for(int i=0;i1]=a[i]-'0';
            hah*=10;
            hah+=shu[i+1];
        }

        if(hah==n)
        {
            printf("%d %d\n",n,n);
            continue; 
        }
        dfs(0,1,1);
        if(flag1)
        {
            puts("rejected");
            continue; 
        }
        if(ans==-1)
            puts("error");
        else
        {
            printf("%d ",ans);
            for(int i=1;i<=lenth;i++)
            {
                printf("%d ",ans1[i]);
            }
            puts(""); 
        }
    }
    return 0;
}

你可能感兴趣的:(===搜索===,DFS)