深度优先搜索笔记1-数字组合问题

《啊哈,算法》中将的深度优先搜索挺好,做个笔记。

问题1:

使用数字1-9组成xxx-xxx=xxx等式,每个数字只能使用一次。

分析:

使用枚举法可以实现,但是需要时间复杂度很高,谁用深度优先搜索比较合适。深度优先搜索的关键在于:解决当下该怎么做,至于下一步该怎么做与当下该怎么做是一样的。将数字1-9比作手里的牌,要发到1-9号箱子里面。需要实现的深度优先搜索的函数dfs(step)确定走到第step个箱子前需要做什么,伪代码:

void dfs(int step)
{
   判断边界
   尝试每一种可能
   for(int i=1;i<=n;i++)
   {
      继续下一步
      dfs(step+1); 
   }
   return;
}

代码

#include<iostream>
#include<vector>

using namespace std;

int a[10], book[10], total = 0; //a数组代表盒子,book数组标记手里的牌是否已经被发出去,total代表方法数


void dfs(int step)
{
	if (step == 10)//如果step=10说明手里的牌已经发完了,可以判断这次排列是否满足要求
	{
		if (a[1] * 100 + a[2] * 10 + a[3] + a[4] * 100 + a[5] * 10 + a[6] == a[7] * 100 + a[8] * 10 + a[9])
		{
			total++;
			printf("method %-3d: %d%d%d+%d%d%d=%d%d%d\n",total,a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
		}
		return;//返回这次函数调用
	}

	for (int i = 1; i <= 9; i++)//走到第step个盒子面前,依次尝试手里的牌(没有被发出去)
	{
		if (book[i] == 0)//等于0说明该牌没有被发出去,还在手里
		{
			a[step] = i;//将这张牌放到盒子里
			book[i] = 1;//标记这张牌已经被发出去了
			dfs(step + 1);//走到下一个盒子发牌
			book[i] = 0;//将发出的这张牌取消标记,因为再次返回到这个盒子时,要尝试其他的牌,这张牌可以用于后续盒子发牌
		}
	}
	return;//处理完成后返回
}
int main()
{
	dfs(1);
	system("pause");
	return 0;
}

这里写图片描述

问题2

输入两个整数 n 和 m,从数列1,2,3…n 中随意取几个数,使其和等于 m,要求将其中所有的可能组合列出来

输入描述

每个测试输入包含2个整数,n和m

输出描述

按每个组合的字典序排列输出,每行输出一种组合

如:
输入:
5 5
输出:
5
1 4
2 3

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

typedef struct Data
{
	int n;
	int m;
	vector<int> book;
	vector<int> box;
};

void dfs(Data& data,int numOfBox,int step,vector<vector<int>>& result)
{
	if (step == numOfBox)
	{
		int sum = 0;
		for (int i = 0; i <numOfBox; i++)
		{
			sum+=data.box[i];
		}
		if (sum == data.m)
		{
			result.push_back(data.box);
		}
		return;
	}

	int start = 1;
	for (int i = data.book.size() - 1; i >= 1; i--)
	{
		if (data.book[i] == 1)
		{
			start = i;
			break;
		}
	}

	for (int i = start; i <= data.n; i++)
	{
		if (data.book[i] == 0)
		{
			data.book[i] = 1;
			data.box.push_back(i);
			dfs(data, numOfBox, step + 1,result);

			data.book[i] = 0;
			data.box.pop_back();
		}
		
	}
	return;
}

void show_1(vector<vector<int>>& v)
{
	for (int i = 0; i < v.size(); i++)
	{
		for (int j = 0; j < v[i].size(); j++)
		{
			cout << v[i][j] << " ";
		}
		cout << endl;
	}
}

void dealResult(vector<vector<int>>& v)
{

}

int main()
{
	Data data;
	vector<vector<int>> result,final;
	cin >> data.n>>data.m;
	for (int i = 0; i <=data.n; i++)
	{
		data.book.push_back(0);
	}
	int sum=0,num;
	for (int i = 1; i < data.n; i++)
	{
		sum += i;
		if (sum >= data.m)
		{
			num = i;
			break;
		}
	}
	if (sum < data.m)
	{
		cerr << "Error: m is too big" << endl;
		system("pause");
		exit(1);
	}
	for (int i =1; i <= num; i++)
	{
		dfs(data, i, 0, result);
	}
	show_1(result);
	system("pause");
	return 0;
}

这里写图片描述

参考文献:《啊哈,算法》–啊哈磊

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值