是时候对于DFS搜索做一个简单的小结了
八皇后问题
解法一:
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <stack>
#include <list>
#include <iomanip>
using namespace std;
///
#define INF 0xffffff7
#define maxn 1010
///
int weight;
int k;
int score[10][10];
int placement[8];
void dfs(int cur, int w)
{
int i, j;
if (cur == 8)
{
if (w > weight)
weight = w;
return;
}
for (i = 0; i < 8; i++)
{
int ok = 1;
placement[cur] = i;
for (j = 0; j < cur; j++)
{
if (placement[cur] == placement[j] || cur - placement[cur] == j - placement[j] || cur + placement[cur] == j + placement[j])
{
ok = 0;
break;
}
}
if (ok)
{
int temp = w + score[cur][i];
dfs(cur + 1, temp);
}
}
}
int main()
{
///
int i, j;
cin >> k;
while (k--)
{
weight = 0;
memset(score, 0, sizeof(score));
memset(placement, 0, sizeof(placement));
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
cin >> score[i][j];
}
}
dfs(0, 0);
cout << setw(5) << weight << endl;
}
///
return 0;
}
方法二:采用
深度优先回溯的另外一种形式
采用stack保存状态,采用set保存状态是否曾经访问过
关键问题在于找到一种唯一表征某一种状态的方式,如果能转化为类似int这种简单形式是最好的
跑了一下,发现比方法一速度慢,原因可能在于状态比较函数比较复杂,如果能简化速度应该能更快
伪代码如下所示
// 深度优先搜索不断的向前寻找可行状态,试图一次找到通向目标状态的道路,它并不会两次访问一个状态,
// 由于某些搜索树包含大量的棋面状态,因此深度优先搜索只是在最大搜索深度固定的情况下才具有可行性,
// 深度优先搜索维护一个栈,保存未访问过的棋面状态。在每次迭代时,深度优先搜索从栈中弹出一个未访问
// 的棋面状态,然后从这个棋面状态开始扩展,根据走法计算其后继棋面状态。如果达到了目标棋面状态,搜
// 索终止。如果没有达到的话,任何在闭合集中后继棋面状态都会被抛弃。剩余的未访问棋面状态被压入栈中,
// 然后继续搜索。伪代码如下:
//
// search (initial, goal)
// if (initial = goal) then return "Solution"
// initial.depth = 0
// open = new Stack
// closed = new Set
// insert(open, copy(initial))
// while (open is not empty) do
// n = pop(open)
// insert(closed, n)
// foreach valid move m at n do
// next = state when playing m at n
// if (closed doesn't contain next) then
// next.depth = n.depth + 1
// if (next = goal) then return "Solution"
// if (next.depth < maxDepth) then
// insert(open, next)
// return "No Solution"
// end
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <stack>
#include <list>
#include <iomanip>
using namespace std;
///
#define INF 0xffffff7
#define maxn 1010
///
int weight;
int k;
int score[10][10];
int placement[8];
struct state{
int w; //当前状态的重量
int nums; //当前已经放置的棋子数目
int place[8]; //当前棋子的排列方式
};
//用于插入set,改变默认的比较函数
struct type_order
{
bool operator()(state const& l, state const& r) const
{
// sort as you want, return true if l < r, false otherwise.
int i;
if (l.nums != r.nums)
return true;
for (i = 0; i < l.nums; i++)
{
if (l.place[i] != r.place[i])
return true;
}
return false;
}
};
void deepth_first_search(const state &initstate)
{
int i, j, k;
stack<state> open;//开放集
set<state, type_order> closed;//闭合集,状态采用state,能转化为更简单表达方式更好
open.push(initstate);
while (!open.empty())
{
state nstate = open.top();
open.pop();
closed.insert(nstate);
//尝试放置,不同问题产生方式不一样,此处为八皇后问题的每一行列值
for (i = 0; i < 8; i++)
{
//产生下一个状态,先复制已有状态的数值
state next;
next.nums = nstate.nums;
next.w = nstate.w;
for (k = 0; k < nstate.nums; k++)
next.place[k] = nstate.place[k];
//检测状态是否满足八皇后棋盘要求
int ok = 1;
next.place[next.nums] = i;
for (j = 0; j < next.nums; j++)
{
if (next.place[next.nums] == next.place[j] || next.nums - next.place[next.nums] == j - next.place[j] || next.nums + next.place[next.nums] == j + next.place[j])
{
ok = 0;
break;
}
}
//如果放置成功
if (ok)
{
next.w += score[next.nums][i];
next.nums++;
//状态没有访问过
if (closed.find(next) != closed.end())
continue;
//更新weight值
if (next.nums == 8)
{
if (next.w > weight)
{
weight = next.w;
}
}
else
open.push(next);
}
}
}
}
int main()
{
///
int i, j;
cin >> k;
while (k--)
{
weight = 0;
memset(score, 0, sizeof(score));
memset(placement, 0, sizeof(placement));
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
cin >> score[i][j];
}
}
//给定初始条件
state initState;
initState.w = 0;
initState.nums = 0;
memset(initState.place, 0, sizeof(initState.place));
deepth_first_search(initState);
cout << setw(5) << weight << endl;
}
///
return 0;
}