UVA 167 苏丹的继承者

是时候对于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;
	
}


 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值