深度优先要比广度优先难一些。
一般来说,一个DFS由三段组成,依次是:结束搜索,状态更新,状态转换。
举两个栗子
有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。
DFS解法:
dfs(id+1,rem-v[id])
,不放入的状态便是dfs(id+1,rem)
。#include
using namespace std;
int cnt, n;
int v[20];
void dfs(int idx, int rem){
//idx是物品标号,rem是剩余空间
if(rem == 0){
cnt++; //方式数加一
return;
}
if(rem < 0 || idx == n - 1) //当空间为负、遍历到最后一个物品仍不符合背包条件时结束
return;
dfs(idx + 1, rem); //两种状态转换
dfs(idx + 1, rem - v[idx + 1]);
}
int main(){
while(cin >> n){
cnt = 0;
for(int i = 0; i < n; i++){
cin >> v[i];
}
dfs(-1, 40); //从-1开始是因为从第0个物品开始就要考虑要与不要两种情况,有点dp的感觉
cout << cnt << endl;
}
return 0;
}
但这样还是有一点动态规划的感觉,因为考虑了放与不放的两个状态转移。
还有一种更容易理解的dfs思想:对于每一次访问,都遍历所有还未被遍历的结点。若容量小于40,则继续遍历;等于40,则方式数加一;大于40,则回溯。
#include
#include
#include
using namespace std;
int n;
int ways=0;
int volume[100]={
0};
bool visit[100]={
false};
void dfs(int index,int v)
{
// cout << "index:" << index << " v:" << v << endl;
if(v == 40){
ways++;
}
else if(v < 40){
visit[index] = true;
for(int i=index;i<=n;i++){
if(visit[i])
continue;
dfs(i,v+volume[i]);//遍历所有还未被遍历的结点
}
visit[index] = false;
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) //volume[0]=0;从1开始存放每个物品
cin >> volume[i];
dfs(0,0); //要是从1开始就相当于使第一个物品必须放入背包
cout << ways << endl;
}
The knight is getting bored of seeing the same black and white squares again and again and has decided to make a journey around the world. Whenever a knight moves, it is two squares in one direction and one square perpendicular to this. The world of a knight is the chessboard he is living on. Our knight lives on a chessboard that has a smaller area than a regular 8 * 8 board, but it is still rectangular. Can you help this adventurous knight to make travel plans?
Find a path such that the knight visits every square once. The knight can start and end on any square of the board.
The input begins with a positive integer n in the first line. The following lines contain n test cases. Each test case consists of a single line with two positive integers p and q, such that 1 <= p * q <= 26. This represents a p * q chessboard, where p describes how many different square numbers 1, . . . , p exist, q describes how many different square letters exist. These are the first q letters of the Latin alphabet: A, . . .
Sample Input
1
4 3
Sample Output
A1B3C1A2B4C2A3B1C3A4B2C4
此题并不难,不过有几点小启示:
visit
标记。第30行的标记取消是因为此时需要回溯,就需要将该点置为未访问;而第19行的标记取消一直到求助了大佬后才想到。原因是我一直想不通为什么仅仅输出了一个解路线就会终止。(当然,该题目仅要求输出一条ascii码序最小的路线,不取消19行的标记才是正确的,因为这样可以抑制后面的输出。但要知道原因)#include
#include
#include
using namespace std;
int m, n;
bool visit[30][30];
void dfs(int row, int col, int steps, string s)
{
if (visit[row][col] || row >= m || row < 0 || col >= n || col < 0) //已访问或不合法
return;
visit[row][col] = 1;
s += 'A' + col;
s += '1' + row;
steps++;
if (steps == m * n) {
cout << s << endl;
visit[row][col] = 0;//要注意这一句
return;
}
dfs(row - 1, col - 2, steps, s);
dfs(row + 1, col - 2, steps, s);
dfs(row - 2, col - 1, steps, s);
dfs(row + 2, col - 1, steps, s);
dfs(row - 2, col + 1, steps, s);
dfs(row + 2, col + 1, steps, s);
dfs(row - 1, col + 2, steps, s);
dfs(row + 1, col + 2, steps, s);
visit[row][col] = 0;
return;
}
int main()
{
cin >> m >> n;
memset(visit, false, sizeof(visit));
dfs(0, 0, 0, "");
return 0;
}
---->
数字以前都是用atof()、atoi()、atol() 实现这一系列转化,但总觉得不方便。索性学了sstream类,用C++中的流来实现这一目的。
#include
#include
#include
using namespace std;
double toDoub(string s)
{
istringstream i(s);//从s中创建输入流
double d;
i >> d;
return d;
}
int main()
{
int t;
string s = "41 3 5 89 300"; //使用空格分隔(默认分隔符)
istringstream i(s);
while(i >> t)
cout << t << endl;
cout << endl;
string ss = "41.5,3.8,5.5,8.9,30.0"; //使用逗号',' 分隔
string tmp;
istringstream ii(ss);
while(getline(ii,tmp,',')){
//配合getline使用,先从整个字符串中提取出每一个小数,设置','为分隔符
cout << toDoub(tmp) << endl; //再用一次输入流转化为double类型
}
}
---->
字符串对于单个字符或许可以用char c = '0' + num;
的形式来转化,但若是多位数字还这样做就太不方便了。当然也可以用C++11支持的to_string()方法。不过 ostringstream也可以解决这个问题。
#include
#include
using namespace std;
string toStr(int n) //当然也可以是double
{
ostringstream o;
if(o << n)
return o.str();
return "";
}
int main()
{
string st = "";
// st += 1234; //error
st += toStr(1234);
cout << st << endl;
}