【第七届蓝桥杯】卡片换位

题目:卡片换位

你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子

+---+---+---+
|  A |  *  |  *  |
+---+---+---+
|  B |     |  *  |
+---+---+---+

在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。
还有一个格子是空着的。

你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。

输入格式:
输入两行6个字符表示当前的局面

输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)

例如,输入:
* A
**B

程序应该输出:
17

再例如,输入:
A B
***

程序应该输出:
12

资源约定:
峰值内存消耗 < 256M
CPU消耗  < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。


以下代码不一定正确,请自己斟酌。

C++代码一:

#include <iostream>
#include <cstdio>
using namespace std;
struct Pos {
	int x, y;
}ap, bp, sp, d;
char s[3][3][3][3][3][3] = {0};
int result = 99999999;
int vis[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};

bool check(Pos v) {
	return v.x > 2 || v.x < 0 ||  v.y > 1 || v.y < 0;
} 
void f(Pos v1, Pos v2, Pos v, int num) {
	if(num > result) return ;
	if(v1.x == bp.x && v1.y == bp.y &&
		v2.x == ap.x && v2.y == ap.y) {
		result = result < num ? result : num;
		return ; 
	}
	if(check(v) || check(v1) || check(v2)) return;
	if(s[v1.x][v1.y][v2.x][v2.y][v.x][v.y] == 1) return;
	s[v1.x][v1.y][v2.x][v2.y][v.x][v.y] = 1;
	for(int i = 0; i < 4; i++) {
		d.x = v.x+vis[i][0];
		d.y = v.y+vis[i][1];
		if(d.x == v1.x && d.y == v1.y)
			f(v, v2, v1, num+1);
		else if(d.x == v2.x && d.y == v2.y)
			f(v1, v, v2, num+1);
		else
			f(v1, v2, d, num+1);
	}
	s[v1.x][v1.y][v2.x][v2.y][v.x][v.y] = 0;
}
void getLineString(int n) {
	char c;
	for(int i = 0; ; i++) {
		c = getchar();
		if(c == '\n') break;
		if(c == ' ') {
			sp.x = i;
			sp.y = n;
		}
		else if(c == 'A') {
			ap.x = i;
			ap.y = n;
		}
		else if(c == 'B') {
			bp.x = i;
			bp.y = n;
		}
	}	
}
int main() {
	getLineString(0); 
	getLineString(1);	
	f(ap, bp, sp, 0);
	cout << result;
	
	return 0;
}

C++代码二:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

//状态结构体
struct State{
	int value[6];
	int dist;
};
int be, en;  //be表示A所在位置,en代表B所在位置
int fact[6];  //用于初始化阶乘的值
//阶乘值的初始化
void init(){
	int i;
	fact[0]=1;
	for(i=1;i<6;i++)
		fact[i]=fact[i-1]*i;
}

int dp[6][6];  //动态规划,用于记录小于的个数(这里可以进一步优化,因为多余1个的数只有0),不失一般性,这里用dp[i][j]记录下标i的数后面数字j的个数
//dp数组的初始化
void getLessNum(int s[]){
	int i,j;
 	memset(dp,0,sizeof(dp));
 	for(i=4;i>=0;i--){
		for(j=0;j<4;j++)
   			dp[i][j]+=dp[i+1][j];
  		dp[i][s[i+1]]++;
 	}
}

//这是将状态编码的方法,返回编码值,利用康托展开
int getMass(int s[]){
	int i,j,ret=0,div=1,less=0;
	getLessNum(s);
	for(i=0;i<5;i++){
  		less=0;
  		div=1;
  		for(j=0;j<4;j++) if(s[i]>j){
   			div*=fact[dp[i][j]];
   			less+=dp[i][j];
  		}
  		ret+=less*fact[5-i]/div;
 	}
 	return ret;
}

//这里是将对应编码转化为对应的状态,即逆康托
State massToState(int mass){
	int i=0,j,be=0,tmass=mass;
 	State ret;
 	int num[4]={3,1,1,1};
 	while(i<6){
  		for(j=be;j<=3;j++) if(num[j]){
   			int tnum;
   			if(!j) tnum=fact[5-i]/fact[num[j]-1];
   			else tnum=fact[5-i]/fact[num[0]];
   			if(tnum>=tmass){
    			ret.value[i]=j;
    			num[j]--;
    			i++;
    			break;
   			}
   			else{
    			tmass-=tnum;
   			}
		}	
 	}
 	return ret;
}

bool vis[120];  //这是判重数组,因为总状态数即A(6,6)/A(3,3)=120种

//这里是bfs的方向偏移数组
int dx[4]={-1,0,1,0};  
int dy[4]={0,1,0,-1};

//这里判断(x,y)是否是合法的点
bool isExceed(int x,int y){
	return x>=0&&x<2&&y>=0&&y<3;
}

queue<State> q;  //bfs所用队列,这里用STL的queue实现

//bfs广度优先搜索,如果不能达到则返回-1
int bfs(int s_b[],int beMass){
 	int i,j;
 	memset(vis,false,sizeof(vis));
 	State b;
 	for(i=0;i<6;i++) b.value[i]=s_b[i];
 	b.dist=0;
 	vis[beMass]=true;
 	q.push(b);
 	while(!q.empty()){
  		State n=q.front();
  		q.pop();
  		if(n.value[be]==2&&n.value[en]==1) 
   			return n.dist;
  		for(i=0;i<6;i++) 
	  		if(n.value[i]==3) 
		  		break; 
  		int nx=i/3;
  		int ny=i%3;
  		for(j=0;j<4;j++){
   			int cnx=nx+dx[j];
   			int cny=ny+dy[j];
   			if(!isExceed(cnx,cny)) continue;
   			int cni=cnx*3+cny;
   			State np=n;
   			int t=np.value[i];
   			np.value[i]=np.value[cni];
   			np.value[cni]=t;
   			int cnMass=getMass(np.value);
   			if(!vis[cnMass]){
    			vis[cnMass]=true;
    			np.dist=n.dist+1;
    			q.push(np);
   			}
  		}	
	}	
 	return -1;
}

int main()
{
 //freopen("test.in","r",stdin);
 	int state_begin[6],i,j;
	char str[10];
 	for(i=0;i<2;i++){
  		gets(str);
  		for(j=0;j<3;j++){
   			if(str[j]=='A') {
			   	state_begin[3*i+j]=1;
				   be=3*i+j;
			}
   			else if(str[j]=='B') {
				state_begin[3*i+j]=2;
				en=3*i+j;
			}
   			else if(str[j]==' ') 
			   state_begin[3*i+j]=3;
   			else state_begin[3*i+j]=0;
  		}
 	}
 	init();
 	getLessNum(state_begin);
 	int mass=getMass(state_begin);
 	int ans=bfs(state_begin,mass);
 	if(ans!=-1) printf("%d\n",ans);
 	else printf("Impossible\n");
 	return 0;
}

C++代码三:

//#include"stdafx.h"
#include <queue>
#include <string>
#include <iostream>
#include <map>
using namespace std;
map<string, int>vis;
struct node{
	int endA;//endA为最终的A的位置,即一开始的B的位置
	int endB;//endA为最终的B的位置,即一开始的A的位置
};
struct point{
	int nowx, nowy;//空格的位置
};
string input(){
	string str1, str2;
	getline(cin, str1);
	getline(cin, str2);
	return str1 + str2;
}
int BFS(string start, node end){
	queue<string> Q;
	string Tr;
	int i;
	int dir[][2] = { { 1,0 },{ 0,1 },{ -1,0 },{ 0,-1 } };
	point S, P;
	Q.push(start);
	vis[start] = 1;
	while (!Q.empty()){
		Tr = Q.front();
		Q.pop();
		if (Tr[end.endA] == 'A'&&Tr[end.endB] == 'B')
			return vis[Tr]-1; 
		for (i = 0;i<6;i++){
   			if (Tr[i] == ' '){
    			S.nowx = i / 3;
    			S.nowy = i % 3;
   			}
		}
  		for ( i = 0;i<4;i++){
   			P.nowx = S.nowx + dir[i][0];
   			P.nowy = S.nowy + dir[i][1];
   			if (P.nowx >= 0 && P.nowx<2 && P.nowy >= 0 && P.nowy<3){
    			string temp = Tr;
    			swap(temp[P.nowx * 3 + P.nowy], temp[S.nowx * 3 + S.nowy]);
    			if (vis[temp]) continue;
    			vis[temp] = vis[Tr] + 1;
    			Q.push(temp);
   			}
 		}
 		
	}
	return -1;
}
int main(){
	int i, j;
 	string start;//每个状态的编码.
 	node end;
 	while (1){
  		start = input();
  		for (i = 0;i < 6;i++){
   			if (start[i] == 'A') end.endB = i;
   			if (start[i] == 'B') end.endA = i;
  		}
  		vis.clear();
  		cout << BFS(start, end) << endl;
 	}	

 	return 0;
}

第七届蓝桥杯所有组试题与部分答案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Homilier

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值