D - 8 Puzzle on Graph题解

atcoder上的一题,感觉挺有意思的就写一下题解,别问我为什么当时没做出来,因为我C题(暴力枚举判断三角形)写爆了,*****,掉大分。

题目链接:D - 8 Puzzle on Graph (atcoder.jp)

题目大意:就是最强大脑里的数字华容道的改版,给你一个3*3的方格阵,有一个空着的,给出初始状态,但是这些方块不能随意移动,他们只能通过给定的凹槽间的边来移动,求出还原成标准状态(数字按大小排好序,如图二,只不过改成了3*3的)最少的移动步数

 

其实翻译一下就是一张无向图有且仅有一个没有数字的中转点,求把所有数字移到指定位置的最少步数,这题N<36所以自然就会想到搜索(绝对不是因为想不到其他方法)。那搜索无非两种,dfs和bfs但是题目要求是输出最小步数,所以两个都可以,这种时候肯定选择又好写,又快的bfs,我们每次找到当前那个空闲着的点,尝试把所有与他相邻的点都移动到这里,然后就会产生新的中转点,那现在的问题就是怎么快速地找到每种情况的中转点,这也是这个题目最巧妙地地方,我们把这张图的每个状态都转化成一个字符串,空闲的点记为9(如下图这个状态就可以转化成字符串”124769853“),这样我们的目标就变成了找到形成”123456789“的最小步数,移动的操作就可以变成交换位置,就很好实现了。(感觉自己表达的不是很清楚,看代码吧,灵魂交流)

#include <bits/stdc++.h>
using namespace std;
vector<int>mp[10];
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		int a,b;
		cin>>a>>b;
		mp[a-1].push_back(b-1);
		mp[b-1].push_back(a-1);
	}
	string a="999999999";//一开始一个数都没有 
	for(int i=1;i<=8;i++){
		int t;
		cin>>t;
		a[t-1]=i+'0';//注意题目给的不是位置对应的数字而是数字对应的位置 
	}
	string aim="123456789";//目标串 
	queue<string>q;
	map<string,int>step;
	q.push(a);
	step[a]=0;
	//常规bfs(这里step就同时起到了判重和记录最小值的作用) 
	while(!q.empty()){
		string x=q.front();
		q.pop();
		int beg=0;
		//找到当前状态的中转点 
		for(int i=0;i<9;i++){
			if(x[i]=='9'){
				beg=i;
			}
		}		
		//枚举所有可能中转到这里的点 
		for(int i=0;i<mp[beg].size();i++){
			string t=x;
			//交换位置 
			swap(t[mp[beg][i]],t[beg]);
			if(step.count(t)!=0){
				continue;
			}else{	
				step[t]=step[x]+1;
				q.push(t);
			}
			//找到了就可以退出了,这题时间复杂度还是挺高的,样例都跑了快一秒 
			if(t==aim){
				break;
			}
		}
	}
	//特判一下不存在的情况 
	if(step.count(aim)==0){
		cout<<"-1"<<endl;
		return 0;	
	}
	cout<<step[aim]<<endl;
	return 0;
}

最后再唠唠我C题怎么写爆的,我第一次写的时候样例没过,我以为是我把两个10^9的数乘起来爆long long了,于是改成了除法,用double开始卡精度,我最后甚至丧心病狂的把相等条件拉到了1e-308(double的最高精度),但是样例还是没过,然后我就开始怀疑这题是不是要上高精度乘,开始去网上找板子,但是越想越不对,这才c题啊,还是个暴力,怎么可能上高精度,于是我就开始找啊找,企图发现哪里写的不对,直到还有十分钟比赛结束时,队友来了,让我改回乘试试,他觉得不会爆,然后就过了,啊这,我当时很有一头撞死的冲动,ab题5分钟写完,罚时7分钟,然后就这样卡到结束,我觉得我要是C没过,应该是两题里面最快的了吧,绝了,退役吧。

Supongo que te gusta

Origin blog.csdn.net/m0_58178876/article/details/120936272
Recomendado
Clasificación