题解P2730 [USACO3.2]魔板 Magic Squares

Link

P2730 [USACO3.2]魔板 Magic Squares

Solve

因为只有8个数的变换,我们直接强刷BFS就可以了,关键是如何判重复的问题,我们发现8的排列数其实不多,也就(8!=40320)所以可以记录下来状态,题解中有很多康托展开的方法非常好,而且效率也很高,说实话就是一种离散的方式,这里给出康拓展开的转移

(X=a[n] imes (n-1)!+a[n-1] imes(n-2)!+...+a[i] imes(i-1)!+...+a[1] imes0!)

其中(a[i])为当前未出现的元素中是排在第几个,也就是后面有几个比我小的。这样转移的非常优秀。

但是我太懒

所以直接用一个map就给水过去了。

哈哈哈哈哈哈哈哈哈哈哈

Code

#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<queue>
using namespace std;
string Ans;
map<string,string> p;
queue<string> Q;
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
void A_(string lst){
	string now=lst;
	for(int i=0;i<4;i++){
		char ch=lst[i];
		now[i]=lst[7-i];
		now[7-i]=ch;
	}
	if(p.count(now)==0){
		Q.push(now);
		p[now]=p[lst]+'A';
	}
	return ;
}
void B_(string lst){
	string now=lst;
	now[0]=lst[3];now[1]=lst[0];now[2]=lst[1];now[3]=lst[2];now[4]=lst[5];now[5]=lst[6];now[6]=lst[7];now[7]=lst[4];
	if(p.count(now)==0){
		Q.push(now);
		p[now]=p[lst]+'B';
	}
	return ;
}
void C_(string lst){
	string now=lst;
	now[1]=lst[6];now[2]=lst[1];now[5]=lst[2];now[6]=lst[5];
	if(p.count(now)==0){
		Q.push(now);
		p[now]=p[lst]+'C';
	}
	return ;
}
void BFS(){
	Q.push("12345678");
	p["12345678"]="";
	while(!Q.empty()){
		A_(Q.front());
		B_(Q.front());
		C_(Q.front());
		if(p.count(Ans)!=0){cout<<p[Ans].size()<<endl<<p[Ans]<<endl;return ;}
		Q.pop();
	}
	return;
}
int main(){
	freopen("P2730.in","r",stdin);
	freopen("P2730.out","w",stdout);
	for(int i=1;i<=8;i++){
		int x=read();
		Ans+=x+'0';
	}
	BFS();
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/13544454.html