DFS的典型例题思考

问题描述

数据压缩的目的是为了减少存储和交换数据时出现的冗余。这增加了有效数据的比重并提高了传输速率。有一种压缩二进制串的方法是这样的:
  将连续的n个1替换为n的二进制表示(注:替换发生当且仅当这种替换减少了二进制串的总长度)
  (译者注:连续的n个1的左右必须是0或者是串的开头、结尾)
  比如:11111111001001111111111111110011会被压缩成10000010011110011。原串长为32,被压缩后串长为17.
  这种方法的弊端在于,有时候解压缩算法会得到不止一个可能的原串,使得我们无法确定原串究竟是什么。请你写一个程序来判定我们能否利用压缩后的信息来确定原串。给出原串长L,原串中1的个数N,以及压缩后的串。
  L<=16 Kbytes,压缩后的串长度<=40 bits。

思考

1.首先这个题目是可以拆分成很多个子问题来解决的,还有就是有点全排列的意思,可以想到用dfs来做。
2.其次就开始思考DFS的结束条件,不符合条件,以及子问题的解决。
3.结束条件就是满足给定的长度符合以及序列中1的个数也符合。
4.不符合条件就是长度超出给定长度,或者得到的1也超出条件。
5.子问题的解决:子问题就是每个小区间的判断以及扩展。
可扩展的序列一定是以1开头,并且结尾的下一位一定是0
特殊小区间的处理:比如说10100可以将前三位展开或者将后三位展开。还有110遇到两个1不用展开。
可扩展的区间就是按二进制转十进制展开。
参数的选择一般就是要达到的目标。将条件和目标定义为全局变量

#include <iostream>
#include <cstdlib>
#include <string>

using namespace std;

int  L;
int l;
int N;
int answer=0;
string s1="";


void compress(int i,int length,int num_1){
	
	if(i==l-1){
		compress(i+1,length+1,num_1+s1[i]-'0');
		return;
	}
	 
	if(i>=l){
		if(length==L&&num_1==N)
			answer++;
		return;
	}
	
	if(length>L||num_1>N||answer>=2){
		return;
	}
	
	if(s1[i]=='0'){
		compress(i+1,length+1,num_1);
		return;
	}
	
	if(s1[i-1]=='1'){
		return;
	}
	
	long long temp=0;
	if(s1[i+1]=='0'){
		compress(i+1,length+1,num_1+1);
	}
	if(s1[i+1]=='1'&&s1[i+2]!='1'){
		compress(i+2,length+2,num_1+2);
	}
	for(int j=i;j<l;j++){
		temp=temp*2;
		temp=temp+s1[j]-'0';
		if(temp+num_1>N||temp+length>L){
			return;
		}
		if(temp>j-i+1&&s1[j+1]!='1'){
			compress(j+1,temp+length,num_1+temp);
		}
	}
	
	
}

int main(){
	cin>>L>>N;
	cin>>s1;
	l=s1.length();
	compress(0,0,0);
	if(answer==0){
		cout<<"NO"<<endl;
	}
	else if(answer==1){
		cout<<"YES"<<endl;
	}
	else{
		cout<<"NOT UNIQUE"<<endl;
	}
	return 0;
}

问题描述

George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

思考

这个是一道经典的DFS+剪枝题目。还是思考这个题目用DFS的原因,要得到最终结果(最小木棍长度)需要尝试很多种组合,而每种组合实现过程基本相同,联系到递归。
1.一个结束条件:木棒用完和一个判断是否成功条件:原木棒数是否正确。
2.最主要的就是剪枝的完整性。第一个考虑木棒长度从大到小排列,因为最终原始木棒长度一定大于切完后的最大长度。而这又带来第二个可剪之处,原始木棒长度从切完后最大长度开始枚举。第三个要考虑如果第一个木棒都没用上那枚举的这个长度就不会成功,直接跳过。如果当前这个木棒没有用上,那么后面与之长度相等的木棒也直接跳过。


#include <iostream>
#include <cstdlib>

using namespace std;

typedef struct sticks {
	int len;
	int visited;
} Sticks;

int cmp(const void *a,const void *b) {
	Sticks *as=(Sticks *)a;
	Sticks *bs=(Sticks *)b;
	return ((as->len<bs->len)?1:-1);
}

int n;
int g;
int len;
Sticks sticks[100];
	
int dfs(int nowlen,int nowget,int cnt) {
	if(cnt>=n)
		return 0;
	if(nowget==g)
		return 1;
	for(int i=cnt;i<n;i++){
		if(sticks[i].visited==0){
			if(sticks[i].len+nowlen==len){
				sticks[i].visited=1;
				if(dfs(0,nowget+1,nowget))
					return 1;
				sticks[i].visited=0;
				return 0;
			}
			else if(sticks[i].len+nowlen<len){
				sticks[i].visited=1;
				if(dfs(nowlen+sticks[i].len,nowget,i+1))
					return 1;
				
				sticks[i].visited=0;
				if(nowlen==0)
					break;
				for(;sticks[i].len==sticks[i+1].len&&i+1<n;i++);
				
			}
		}
	}
	return 0;
	
}


int main() {

	scanf("%d",&n);
	while(n) {
		int sum=0;

		for(int i=0; i<n; i++) {
			sticks[i].visited=0;
		}

		for(int i=0; i<n; i++) {
			scanf("%d",&sticks[i].len);
			sum+=sticks[i].len;
		}

		qsort(sticks,n,sizeof(sticks[0]),cmp);
		
		for(len=sticks[0].len; len<=sum; len++) {
			if(sum%len!=0)
				continue;
			g=sum/len;
			if(dfs(0,0,0))
				break;
		}

		cout<<len<<endl;

		cin>>n;
	}

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值