洛谷 P5507 【机关】题解

题目

基本思路和算法(A*)大佬们都讲的很详细了(不会的点这里),这里就提供一个小小的但很实用优化。

离AC只差一步的可以来看看

《算法竞赛进阶指南》第124页写到“估价函数的估值不能大于未来的实际价值”,但在这题中,稍稍提高一点估值可以大大提高程序运行效

优化前

优化后

优化前后效率快了将近一倍,而优化所做的所有改变就是在估价函数上乘了一个系数

一般的估价函数:每个旋钮距离目标状态(1)的差值之和除以2(取上整)

bool operator < (const e &a) const {
      return s + (v >> 1) + (v & 1) > a.s + (a.v >> 1) + (a.v & 1);
}

注:

1、s指当前状态已经操作的次数,v表示每个旋钮距离目标状态的差值之和(估价函数)

2、加上(v&1)是为了取上整(也许没什么用)

3、该比较函数写在结构体中,结构体名称为e

不难发现,这个估价函数是一个很美好的理想状态(每次操作都让两个旋钮向目标状态靠近),但现实中很难达到,可以让估值更准确一些,于是我在 v 上乘一个稍大于1的系数(1.1, 1.2, 1.3)均可(下面代码中写的1.3,因为这个比较快),可以自己调试

变成这样:

bool operator < (const e &a) const {
      return s + (v >> 1) * 1.3 + (v & 1) > a.s + (a.v >> 1) * 1.3 + (a.v & 1);
}

小小的改变就上效率大大提高,快了将近400ms(数据最大的点快了300ms,虽然巨佬们总用时都不到300ms

完整代码

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#define x now[a[p][now[p]]]
#define y now[p]
int tx, a[13][5], k[30000000], to[5] = {0, 2, 3, 4, 1};
struct e {
	int s, sum, v, now[13], step[20];
	bool operator < (const e &a) const {
      return s + (v >> 1) * 1.3 + (v & 1) > a.s + (a.v >> 1) * 1.3 + (a.v & 1);
    }
    inline void change (int p) {
		x = to[x], tx = x, y = to[y];
		v += (tx == 2) * 3 - (tx != 2) + (y == 2) * 3 - (y != 2);
    	step[++s] = p, sum += (tx == 1) - (tx == 2) + (y == 1) - (y == 2);
	}
	inline int get () {
		int tmp(0);
		for (int i = 1; i <= 12; ++i)  tmp = (tmp << 2) + now[i];
		return tmp;
	}
} top, tmp, t;
void Just_Do_It () {
	priority_queue <e> q;
	q.push (top);
	while (!q.empty()) {
		tmp = q.top();  q.pop();
		for (int i = 12; i; --i) {
			t = tmp;
			t.change (i);
			if (t.sum == 12) {
				printf ("%d
", t.s);
				for (int i = 1; i <= t.s; ++i) printf ("%d ", t.step[i]);
				return;
			}
			int tt (t.get());
			if (k[tt]) continue;
			k[tt] = 1;
			q.push (t);
		}
	}
}
int main() {
	for (int i = 1; i <= 12; ++i) 
		scanf ("%d %d %d %d %d", &top.now[i], &a[i][1], &a[i][2], &a[i][3], &a[i][4]);
	for (int i = 1; i <= 12; ++i)  
	  top.sum += (top.now[i] == 1), top.v += (top.now[i] == 1) ? 0 : 5 - i;
	k[top.get()] = 1;
	Just_Do_It ();
	return 0;
} 
原文地址:https://www.cnblogs.com/whx666/p/11409447.html