这个专题是记录罗勇军《算法竞赛入门到进阶》DFS练习题的做题感悟。
poj 1416 "Shredding Company"
分岔路:以“12346”为例,可能的切割点:0号位置、1号位置、2号位置、3号位置、4号位置共计5个。因此,每次深度优先就以是否在i号位置进行切割为选择。用bool cut[ ]数组来记录是否切割。
终止:当5个位置的切割情况都已经确定后就终止。
注意点:50 12346这个测试数据会出现这两种切割: 0、1、3号切割其余位置不切割得 43 1 2 34 6;
0、1、3、4号位置切割其余位置不切割得 43 1 2 34 6。这两种虽然cut[]数组不一样,但是属于同种切割,在判断rejected时需要注意这个点。
另外,如果出现字符串的非首尾位置中出现0的情况,比如12034,答案要么是12034 12034;要么是error;要么是rejected;因此输出可以大胆以%d的形式输出,不必在输出时考虑可能会输出类似“0xx"如”034“的情况。
ps:深度优先搜索有时候就像写个多重循环。当拿到一个题目像是要写循环但是知道要写很多重或者不知道要写多少重时就可以考虑用深度优先搜索解决。采用深度优先搜索解决问题时要注意问题的分岔路和终止条件,当然有时候还需要灵活的剪枝。
AC代码:
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int n;
char s[7];
bool cut[7];
vector<int> path;
int nearest = -1, num = 0;
int Stoi(char s[], int begin, int end)
{
int ans = 0;
for(int i=begin; i<=end; i++){
ans = ans*10+s[i]-'0';
}
return ans;
}
void dfs(int step, int len)
{
if(step==len){
int begin=0;
int total=0;
vector<int> tmp;
for(int i=0; i<len; i++){
if(cut[i]==true){
int num = Stoi(s,begin,i);
tmp.push_back(num);
total+=num;
begin = i+1;
if(begin>=len) break;
}
}
if(begin<len){
int num = Stoi(s,begin,len-1);
tmp.push_back(num);
total+=num;
}
if(total>n) return;
if(total>nearest){
nearest = total;
path = tmp;
num = 1;
}
else if(total==nearest){
if(tmp.size()!=path.size()){
num++;
}
else{
for(int i=0; i<tmp.size(); i++){
if(tmp[i]!=path[i]){
num++;
break;
}
}
}
}
return;
}
cut[step]=false;
dfs(step+1,len);
cut[step]=true;
dfs(step+1,len);
}
int main()
{
scanf("%d%s",&n,s);
while(true){
int len = strlen(s);
if(n==0&&Stoi(s,0,len-1)==0){
break;
}
path.clear();
nearest=-1;
num=0;
dfs(0,len);
if(num>1){
printf("rejected\n");
scanf("%d%s",&n,s);
continue;
}
if(path.size()==0){
printf("error\n");
scanf("%d%s",&n,s);
continue;
}
printf("%d",nearest);
for(int i=0; i<path.size(); i++){
printf(" %d",path[i]);
}
printf("\n");
scanf("%d%s",&n,s);
}
return 0;
}