深度优先搜索专题

这个专题是记录罗勇军《算法竞赛入门到进阶》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;
}



 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值