POJ 1416 -- Shredding Company

 POJ 1416 -- Shredding Company

题意:

公司现在要发明一种新的碎纸机,要求新的碎纸机能够把纸条上的数字切成最接近而不超过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.
你的任务是编写程序对数字进行划分以达到最佳值。

解题思路:
DFS

(1)比如一个6位数n,切成为6个数的话,这6个数的和如果大于目标数target则不用再搜索了,因为这肯定是所有划分中和最小的,而最小都比目标数大,自然就没有合要求的答案了.
(2) 如何切分,假如以50  12346 为例。
第一步,先切下一个“1”,然后递归去切“2346”;
第二步,再切下一个“12”,然后递归去切“346”;
第三步,再切下一个“123”,然后递归去切“46”;
第四步,再切下一个“1234” 然后递归去切“6” 
第五步,再切下“12346”。

(3)切下来的 前面的数字串部分 则加入到划分的和,剩下的部分继续递归,直到已经划分出来的数字长度len等于数字串总长度strlen(num)。为了记录划分方式,使用int数组devide记录每一次划分的长度,比如样例50 12346划分为43 1 2 34 6,那devide[0] = 1,devide[1] = 1,devide[2] = 2,devide[3] = 1。而且为了保存最优解,需要在已经划分出来的数字长度len等于数字串总长度strlen(num),并且abs(bestx-target)>abs(sum-target)时,更新最优解bestx = sum,并且将devide转存到ansdevide中,为了方便之后答案的输出。

(4)使用字符数组存储数字串num,这样在搜索时,只要控制字符数组的起止位置就可以模拟数字串的拆分。

(5)剪枝方法:在搜索时若发现部分和 大于(不能等于)target时,则可结束搜索。

在进入dfs搜索时,可以把特殊情况排除

  1)error的判定要在搜索前进行

  2)当数字串num和target相等时,直接输出,不用划分

  3)当数字串的每一位数字之和sum2等于target时,直接逐位输出,每个数字为一个划分

     注意这种情况有一个特例,就是0出现的时候,

    例如样例:6 1104

    它的最优划分有两种 6 1 1 0 4

              6 1 1 04

    所以此样例应该输出rejected

    所以这种情况下,应该保证数字串num中没有0,才可以直接逐位输出

(6)rejected(多个最优解)的判定要在搜索后判定。当最优解出现两次的时候(出现abs(bestx-target)==abs(sum-target)),使用全局变量Count计数

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int target;
 6 char num[10];
 7 int bestx;
 8 int Count;
 9 int anslen;
10 int ansdevide[10];
11 void dfs(char *ch,int len,int sum,int c,int *devide)
12 {///len为当前已经划分的数字串的长度,sum为当前已划分的数字的总和
13 ///c为划分的数字的块数
14     if(len == strlen(num))
15     {
16         if(abs(bestx-target)>abs(sum-target))
17         {
18             Count=0;
19             anslen = c;
20             bestx = sum;
21             for(int i=0;i<c;i++)
22                 ansdevide[i] = devide[i];
23             return;
24         }
25         if(abs(bestx-target)==abs(sum-target))///出现多个最优解
26         {
27             Count++;
28         }
29         return;
30     }
31     for(int i=1;i<=strlen(ch);i++)
32     {///确定下一步划分的长度i
33         int newsum = 0;
34         for(int j=0;j<i;j++)
35             newsum = newsum*10 + (ch[j]-'0');
36         newsum+=sum;
37         devide[c] = i;
38         if(newsum<=target)
39             dfs(ch+i,len+i,newsum,c+1,devide);
40     }
41 }
42 
43 int main()
44 {
45     while(cin>>target && target)
46     {
47         cin>>num;
48         int sum1 = 0;///计算纸上的数是多少
49         int sum2 = 0;///每一位的和
50         for(int i=0;i<strlen(num);i++)
51         {
52             sum1 = sum1*10+(num[i]-'0');
53             sum2 += num[i]-'0';
54         }
55         if(sum1 == target)
56             cout<<target<<" "<<target<<endl;
57         else if(sum2 > target)
58         {
59             cout<<"error"<<endl;
60         }
61         else if(sum2 == target && !strchr(num,'0'))
62         {
63             cout<<target;
64             for(int i=0;i<strlen(num);i++)
65             {
66                 cout<<" "<<num[i];
67             }
68             cout<<endl;
69         }else
70         {
71             Count = 0;
72             bestx = 0;
73             int devide[10];
74             dfs(num,0,0,0,devide);
75             if(Count > 0)
76                 cout<<"rejected"<<endl;
77             else{
78                 cout<<bestx;
79                 int temp=0;
80                 for(int i=0;i<anslen;i++)
81                 {
82                     cout<<" ";
83                     for(int j=temp;j<temp+ansdevide[i];j++)
84                     {
85                         cout<<num[j];
86                     }
87                     temp += ansdevide[i];
88                 }
89                 cout<<endl;
90             }
91         }
92 
93     }
94     return 0;
95 }

 

posted @ 2018-02-23 20:11  卉卉卉大爷  阅读(136)  评论(0编辑  收藏  举报