zoukankan      html  css  js  c++  java
  • 【反向BFS+康托展开】Eight HDU

    Eight

    题意:八数码问题

    思路:反向BFS+康托展开

    const int maxn = 362885;
    
    const int FAC[] = { 1,1,2,6,24,120,720,5040,40320,362880,3628800 };
    
    int cantor(int* a) {//算出全排列对应的哈希值
    	int x = 0;
    	for (int i = 0; i < 9; i++) {
    		int smaller = 0;
    		for (int j = i + 1; j < 9; j++) {
    			if (a[j] < a[i]) smaller++;
    		}
    		x += FAC[9 - i - 1] * smaller;
    	}
    	return x;
    	//注意全排列数组a是从零开始的
    }
    
    
    void decantor(int x, int*ans) {//x哈希值,n数字个数,a算出的全排列
    
    	vector<int> v;
    	for (int i = 1; i <= 9; i++) v.push_back(i);
    	for (int i = 0; i < 9; i++) {
    		int r;
    		r = x / FAC[9 - i - 1];
    		x = x % FAC[9 - i - 1];
    		sort(v.begin(), v.end());
    		ans[i] = v[r];
    		v.erase(v.begin() + r);
    	}
    	//注意算出的全排列数组ans是从0开始的
    
    }
    
    //描述每个状态需要有以下信息
    struct node {
    	int hash;
    	int pos;
    	int pre;
    };
    
    string path[maxn];//下标是一个状态的哈希值,表示从该状态到达目标状态的路径
    bool vis[maxn];
    int dx[] = { 1,-1,0,0 };
    int dy[] = { 0,0,-1,1 };
    char dir_op[5] = "udrl";
    //反向bfs,所以路径记录和实际运算反着来,如空格坐标运算为下移一行时,路径记录为u
    
    void bfs() {
    	queue<node> q;
    
    	node temp;
    	int a[10];
    	for (int i = 0; i < 9; i++) a[i] = i + 1;
    	//反向bfs
    	//故目标状态即起始状态,即123456789
    	temp.hash = cantor(a);
    	temp.pre = -1;
    	temp.pos = 8;//从0起计,代表空格的9在状态数组中下标为8
    	path[temp.hash] = "";
    
    	q.push(temp);
    	vis[temp.hash] = 1;
    	while (!q.empty()) {
    		temp = q.front();
    		q.pop();
    		int sx = temp.pos / 3;
    		int sy = temp.pos % 3;
    		decantor(temp.hash, a);
    		//逆运算得到该节点状态数组
    		for (int i = 0; i < 4; i++) {
    			int nx = sx + dx[i];
    			int ny = sy + dy[i];
    			int npos = nx * 3 + ny;
    			//换位后空格所在的新位置
    			if (nx < 0 || ny < 0 || nx>2 || ny>2) continue;
    			swap(a[temp.pos], a[npos]);
    			//换位置后的状态数组再算出哈希值
    			int nval = cantor(a);
    			if (vis[nval]) {
    				swap(a[temp.pos], a[npos]);
    				//如果该状态已经遇到过,复原回去,继续尝试其他换位
    				continue;
    			}
    			node t;
    			t.hash = nval;
    			t.pos = npos;
    			t.pre = temp.hash;
    			//记录该状态的上一状态的哈希值
    			path[nval] = dir_op[i] + path[temp.hash];
    			//注意因为是反向bfs,移动记录的顺序也是反着的
    			//如从某状态经udlr到达状态123456789
    			//而代码从123456789开始运算,是经lrud到达该状态的
    			//其中“方向相反”已在定义dir_op时完成,只要将新的操作记在之前所有操作的最前面即可
    
    			q.push(t);
    			vis[nval] = 1;
    			//新状态入队并记录
    			swap(a[temp.pos], a[npos]);
    			//复原回去,继续尝试其他换位
    		}
    	}
    	
    }
    
    int main()
    {
    	//ios::sync_with_stdio(false);
    	//int t; cin >> t; while (t--){
    	string s;
    	memset(vis, 0, sizeof(vis));
    	bfs();
    	//bfs一次解决所有多组样例
    	int a[10];
    	while (getline(cin, s)) {
    		int j = 0;
    		for (int i = 0; i < s.size(); i++) {
    			if (s[i] == 'x') a[j++] = 9;
    			else if (isdigit(s[i])) a[j++] = s[i] - '0';
    		}
    		int ans = cantor(a);
    		if (vis[ans]) {
    			cout << path[ans] << endl;
    		}
    		else cout << "unsolvable" << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    VS2017 C# winform 项目使用 sqlite (二)
    VS2017 C# winform 项目使用 sqlite (一)
    JS权威指南笔记(171页)-this关键字的作用域
    量化交易之下单函数和context对象
    量化交易策略基本框架
    初始量化交易
    金融量化之Tushare模块
    Python之基础算法介绍
    数据分析之Matplotlib和机器学习基础
    数据分析之Pandas
  • 原文地址:https://www.cnblogs.com/streamazure/p/13369588.html
Copyright © 2011-2022 走看看