题目:卡片换位
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 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>, 不能通过工程设置而省略常用头文件。
第七届蓝桥杯所有组试题与部分答案
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 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;
}
第七届蓝桥杯所有组试题与部分答案