这题难度颇大啊,TLE一天了,测试数据组数太多了。双向广度优先搜索不能得到字典序最小的,一直WA。

思路:利用IDA*算法,当前状态到达目标状态的可能最小步数就是曼哈顿距离,用于搜索中的剪枝。下次搜索的限制不能直接加1,会超时,应该从当前状态到目标状态最小限制开始搜索。

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 4e5 + 5;
int vis[maxn];
int st[9], goal[9];

const int dx[] = {1,0,0,-1};
const int dy[] = {0,-1,1,0};
const char dir[] = {'d','l','r','u'};

int fact[9], loc[9];
void deal() {  //1~8阶乘打表,方便编码
	fact[0] = 1;
	for(int i = 1; i < 9; ++i) fact[i] = fact[i - 1] * i;
}

int KT(int *a) {
	int code = 0;
	for(int i = 0; i < 9; ++i) {
		int cnt = 0;
		for(int j = i + 1; j < 9; ++j) if(a[j] < a[i]) cnt++;
		code += fact[8 - i] * cnt;
	}
	return code;
} 

void get_pos() {
	for(int i = 0; i < 9; ++i) {
		loc[goal[i]] = i;
	}
}

int get_h(int *a) { //曼哈顿距离
	int cnt = 0;
	for(int i = 0; i < 9; ++i) {
		if(a[i] == 0 || i == loc[a[i]]) continue;
		int x = i / 3, y = i % 3;
		int n = loc[a[i]];
		int px = n / 3, py = n % 3;
		cnt += abs(x - px) + abs(y - py);
	}
	return cnt;
}

char ans[50];
int a[9];

// step + h <= maxd
int maxd, nextd;
int dfs(int step, int pos) {
	int h = get_h(a); // cut
	//printf("h = %d\n", h);
	if(h == 0) {
		printf("%d\n", step);
		ans[step] = '\0';
		printf("%s", ans);
		return 1;
	}
	if(step + h > maxd) {
		nextd = min(nextd, step + h);
		return 0;
	}
	int x = pos / 3, y = pos % 3;
	for(int i = 0; i < 4; ++i) {
		int px = x + dx[i], py = y + dy[i];
		if(px < 0 || py < 0 || px >= 3 || py >= 3) continue;
		int pz = px * 3 + py;
		swap(a[pos], a[pz]);
		int code = KT(a);
		if(vis[code]) {
			swap(a[pos], a[pz]);
			continue;
		}
		vis[code] = 1;
		ans[step] = dir[i];
		if(dfs(step + 1, pz)) return 1;
		vis[code] = 0;
		swap(a[pos], a[pz]);
	}
	return 0;
} 

int main() {
	deal();
	char str[50];
	int T, kase = 1;
	scanf("%d", &T);
	while(T--) {
		int pos;
		scanf("%s", str);
		for(int i = 0; i < 9; ++i) {
			if(str[i] == 'X') {
				pos = i;
				st[i] = 0;
			}
			else st[i] = str[i] - '0';
		}

		scanf("%s", str);
		for(int i = 0; i < 9; ++i) {
			if(str[i] == 'X') goal[i] = 0;
			else goal[i] = str[i] - '0';
		}
		get_pos();

		printf("Case %d: ", kase++);

		int code = KT(st);
		vis[code] = 1;
		for(maxd = get_h(st);;) {
			nextd = 1 << 30;
			memcpy(a, st, sizeof(a));
			memset(vis, 0, sizeof(vis));
			if(dfs(0, pos)) break;
			maxd = nextd;
		}
		printf("\n");
	}
	return 0;
}

如有不当之处欢迎指出!

HDU - 3567 IDA* + 曼哈顿距离 + 康托 [kuangbin带你飞]专题二的更多相关文章

  1. HDU - 1043 A* + 康托 [kuangbin带你飞]专题二

    这题我第一次用的bfs + ELFhash,直接TLE,又换成bfs + 康托还是TLE,5000ms都过不了!!我一直调试,还是TLE,我才发觉应该是方法的问题. 今天早上起床怒学了一波A*算法,因 ...

  2. HDU - 3085 双向BFS + 技巧处理 [kuangbin带你飞]专题二

    题意:有两只鬼,一个男孩女孩被困在迷宫中,男孩每秒可以走三步,女孩只能1步,鬼可以两步且可以通过墙.问男孩女孩是否可以在鬼抓住他们之前会合? 注意:每秒开始鬼先移动,然后两人开始移动. 思路:以男孩和 ...

  3. HDU - 3567 Eight II (bfs预处理 + 康托) [kuangbin带你飞]专题二

    类似HDU1430,不过本题需要枚举X的九个位置,分别保存状态,因为要保证最少步数.要保证字典序最小的话,在扩展节点时,方向顺序为:down, left, right, up. 我用c++提交1500 ...

  4. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  5. HDU - 3533 bfs [kuangbin带你飞]专题二

    看了好久的样例才看懂. 题意:有一个人要从(0,0)走到(n,m),图中有k个碉堡,每个碉堡可以向某个固定的方向每隔t秒放一次炮,炮弹不能穿越另一个碉堡,会被阻挡.人在移动的过程中不会被炮弹打到,也就 ...

  6. HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二

    终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...

  7. HDU1560 DNA sequence IDA* + 强力剪枝 [kuangbin带你飞]专题二

    题意:给定一些DNA序列,求一个最短序列能够包含所有序列. 思路:记录第i个序列已经被匹配的长度p[i],以及第i序列的原始长度len[i].则有两个剪枝: 剪枝1:直接取最长待匹配长度.1900ms ...

  8. HDU - 1067 Gap (bfs + hash) [kuangbin带你飞]专题二

    题意:    起初定28张卡牌的排列,把其中11,  21, 31, 41移动到第一列,然后就出现四个空白,每个空白可以用它的前面一个数的下一个数填充,例如43后面的空格可以用44填充,但是47后面即 ...

  9. HDU - 2102 A计划 (BFS) [kuangbin带你飞]专题二

    思路:接BFS判断能否在限制时间内到达公主的位置,注意如果骑士进入传送机就会被立即传送到另一层,不会能再向四周移动了,例如第一层的位置(x, y, 1)是传送机,第二层(x, y, 2)也是传送机,这 ...

随机推荐

  1. tomcat server.xml context path配置需要注意的事情

    在tomcat下放个war包,假如我是这样配置server.xml的,<Context docBase="eggchina" path="/yanan" ...

  2. 流API--缩减操作

    在Stream流操作中,比如说min(),max(),count()方法,这几个操作都会将一个流缩减成一个值,流API将这些操作称为特例缩减.另外,流API同时泛华了缩减这种概念,提供了reduce( ...

  3. NDk编译opencv for Android,并引用在Unity3d游戏中的一般步骤

    本文使用:Unity3d + opencv + Android Unity3d中可以调用opencv 编译好的.so 动态库,在生成Android apk时可以正常运行.   因为Android系统是 ...

  4. Linux下MongoDB安装和配置详解

    1.下载安装包 将解压到/usr/local/mongodb 文件夹下 # mkdir /usr/local/mongodb # tar zxvf mongodb-linux-x86_64-3.2.9 ...

  5. error_reporting

    有关error_reporting()函数: error_reporting() 设置 PHP 的报错级别并返回当前级别. ; 错误报告是按位的,或者将数字加起来得到想要的错误报告等级. ; E_AL ...

  6. 《.NET 设计规范》第 5 章:成员设计

    <.NET 设计规范>第 5 章:成员设计 5.1 成员设计的通用规范 要尽量用描述性的参数名来说明在较短的重载中使用的默认值. 避免在重载中随意地改变参数的名字.如果两个重载中的某个参数 ...

  7. SAP字符串处理

    拼接字符串 CONCATENATE t1 t2 INTO result. "直接拼接 CONCATENATE t1 t2 INTO result SEPARATED BY space. &q ...

  8. Linux history命令

    history命令主要用于显示历史命令, 重新执行历史命令. Linux系统当你在shell(控制台)中输入并执行命令时,shell会自动把你的命令记录到历史列表中,一般保存在用户目录下的.bash_ ...

  9. CTSC 2017 滚粗记

    CTSC 2017 滚粗记 结束好几天了一直没写. 明天就要去参加二轮省选了,填一下坑吧. 所以可能很多东西已经忘了 Day -2 [5.5 Fri] 周五晚上是其他学信竞的同学来机房的时间... 也 ...

  10. codechef Dynamic GCD [树链剖分 gcd]

    Dynamic GCD 题意:一棵树,字词树链加,树链gcd 根据\(gcd(a,b)=gcd(a,a-b)\) 得到\(gcd(a_1, a_2, ..., a_i) = gcd(a_1, a_1- ...