10.13—广搜 //特殊的二阶魔方//推箱子//polygon//木乃伊迷宫

探讨特殊二阶魔方还原与推箱子游戏的最短路径算法,涉及状态空间搜索、广度优先搜索(BFS)及游戏状态表示,解决复杂问题的高效策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.特殊的二阶魔方

描述:魔方大家应该都玩过。现在有一个特殊的二阶魔方,它只有一面是白色,其余五个面全是黑色。玩这个魔方当然也有特殊的规则,玩家只能通过六种方式去改变它,底层向左转一格(称为DL),底层向右转一格(称为DR),右侧向上转一格(称为RU),右侧向下转一格(称为RD),内侧顺时针转一格(称为C),内侧逆时针转一格(称为CC)。现给一魔方的状态,请在最少的步骤内把魔方还原

输入:按照上下左右前后的顺序给出各面的具体情况,0表示白色,1表示黑色。上下、左右、前后分别是以俯视图、左视图、正视图看到的

输出:输出令一面全为白色的最小步数。

输入样例:

00
00
11
11
11
11
11
11
11
11
11
11

输出样例:

0

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

struct node
{
	int num[6]; 
    int cube[6][4]; 
};

queue <node> q1;
int step[16][16][16][16][16][16];
int used[16][16][16][16][16][16]; 
int bfs(); 
node setnum(node n1);  
node moveto(node n1, int d);  
int canmoveto(node n1, node n2);   //对n2节点进行判重
int judge(node n1); 
      
int main()
{
    node start;
    for(int i=0; i<6; i++)
    {
        for(int j=0; j<4; j++)
        {
            start.cube[i][j]=cin.get()-'0'; 
 
            if(j==1)cin.get();
        }
        cin.get();
    }
    start=setnum(start); 
 
    if(judge(start)) 
    {
        cout<<'0'<<endl;
    }
    else
    {
        q1.push(start); 

        step[start.num[0]][start.num[1]][start.num[2]][start.num[3]][start.num[4]][start.num[5]]=0;
        used[start.num[0]][start.num[1]][start.num[2]][start.num[3]][start.num[4]][start.num[5]]=1;

        cout<<bfs()<<endl;
    }
    return 0;
}
 
int bfs()
{
    node top,next;
    while(!q1.empty())
    {
        top=q1.front();
        q1.pop();
 
        for(int i=0; i<6; i++)
        {
            next=moveto(top,i);
            if(canmoveto(top, next))
            {
                if(judge(next))  
                {
                    return step[next.num[0]][next.num[1]][next.num[2]][next.num[3]][next.num[4]][next.num[5]];
                }
                else 
                {
                    q1.push(next);
                }
            }
        }
    }
    return -1;
}
 
 
node setnum(node n1)
{
    for(int i=0; i<6; i++)  //六个面
    {
        n1.num[i]=0;        //清空num
 
        for(int j=0; j<4; j++)  //每面4块,0==白,1==黑,当作4位二进制编码
        {
            n1.num[i]*=2;       //把4位二进制编码转换成十进制,范围应是0-15
            n1.num[i]+=n1.cube[i][j];
        }
    }
    return n1;  //返回填充了num数组的n1节点
}


//判断n1节点是否到达目标状态
int judge(node n1)
{
	int i;
    for(i=0; i<6; i++)
    {
        if(n1.num[i]==0)    //目标状态为一面有四个白块,二进制编码为0000
        {
            return 1;    //6个面里只要有一个面为0
        }
    }
    return 0;
}
 
//判断n2节点是否重复
int canmoveto(node n1, node n2)
{
    if(used[n2.num[0]][n2.num[1]][n2.num[2]][n2.num[3]][n2.num[4]][n2.num[5]]==1)
    {
        return false;   //如果重复就返回false
    }
    else    //如果没重复就更新
    {
        //更新used数组,记录n2节点用过
        used[n2.num[0]][n2.num[1]][n2.num[2]][n2.num[3]][n2.num[4]][n2.num[5]]=1;
 
        //更新step数组,到达n2节点所用步数=1+到达n1节点所用步数
        step[n2.num[0]][n2.num[1]][n2.num[2]][n2.num[3]][n2.num[4]][n2.num[5]]=
            1+step[n1.num[0]][n1.num[1]][n1.num[2]][n1.num[3]][n1.num[4]][n1.num[5]];
 
        //返回true表示不重复
        return true;
    }
}

node moveto(node n1, int dire)
{
    node n2;   
    for(int i=0; i<6; i++)
    {
        for(int j=0; j<4; j++)
        {
            n2.cube[i][j]=n1.cube[i][j]; 
        }
    }
    
    switch(dire)
    {
    	 case 0: //右侧向上转一格
        {
            n2.cube[0][1]=n1.cube[4][1];    //上面的1、3块=前面的1、3块
            n2.cube[0][3]=n1.cube[4][3];
 
            n2.cube[4][1]=n1.cube[1][3];    //前面的1、3块=下面的3、1块
            n2.cube[4][3]=n1.cube[1][1];
 
            n2.cube[1][1]=n1.cube[5][1];    //下面的1、3块=后面的1、3块
            n2.cube[1][3]=n1.cube[5][3];
 
            n2.cube[5][1]=n1.cube[0][3];    //后面的1、3块=上面的3、1块
            n2.cube[5][3]=n1.cube[0][1];
 
            n2.cube[3][0]=n1.cube[3][1];    //右面的4个块逆时针转
            n2.cube[3][1]=n1.cube[3][3];
            n2.cube[3][3]=n1.cube[3][2];
            n2.cube[3][2]=n1.cube[3][0];
 
            break;
        }
        
        case 1: //右侧向下转一格
        {
            n2.cube[0][1]=n1.cube[5][3];    //上面的1、3块=后面的3、1块
            n2.cube[0][3]=n1.cube[5][1];
 
            n2.cube[5][1]=n1.cube[1][1];    //后面的1、3块=下面的1、3块
            n2.cube[5][3]=n1.cube[1][3];
 
            n2.cube[1][1]=n1.cube[4][3];    //下面的1、3块=前面的3、1块
            n2.cube[1][3]=n1.cube[4][1];
 
            n2.cube[4][1]=n1.cube[0][1];    //前面的1、3块=上面的1、3块
            n2.cube[4][3]=n1.cube[0][3];
 
            n2.cube[3][0]=n1.cube[3][2];    //右面的4个块顺时针转
            n2.cube[3][2]=n1.cube[3][3];
            n2.cube[3][3]=n1.cube[3][1];
            n2.cube[3][1]=n1.cube[3][0];
 
            break;
        }
        
        case 2: //底层向左转一格
        {
            n2.cube[2][2]=n1.cube[4][2];    //左面的2、3块=前面的2、3块
            n2.cube[2][3]=n1.cube[4][3];
 
            n2.cube[4][2]=n1.cube[3][3];    //前面的2、3块=右面的3、2块
            n2.cube[4][3]=n1.cube[3][2];
 
            n2.cube[3][2]=n1.cube[5][2];    //右面的3、2块=后面的2、3块
            n2.cube[3][3]=n1.cube[5][3];
 
            n2.cube[5][2]=n1.cube[2][3];    //后面的2、3块=左面的3、2块
            n2.cube[5][3]=n1.cube[2][2];
 
            n2.cube[1][1]=n1.cube[1][0];    //下面的4个块顺时针转
            n2.cube[1][0]=n1.cube[1][2];
            n2.cube[1][2]=n1.cube[1][3];
            n2.cube[1][3]=n1.cube[1][1];
 
            break;
        }
        
        case 3: //底层向右转一格
        {
            n2.cube[3][2]=n1.cube[4][3];    //右面的2、3块=前面的3、2块
            n2.cube[3][3]=n1.cube[4][2];
 
            n2.cube[4][2]=n1.cube[2][2];    //前面的2、3块=左面的2、3块
            n2.cube[4][3]=n1.cube[2][3];
 
            n2.cube[2][2]=n1.cube[5][3];    //左面的2、3块=后面的3、2块
            n2.cube[2][3]=n1.cube[5][2];
 
            n2.cube[5][2]=n1.cube[3][2];    //后面的3、2块=右面的2、3块
            n2.cube[5][3]=n1.cube[3][3];
 
            n2.cube[1][2]=n1.cube[1][0];    //下面的4个块逆时针转
            n2.cube[1][3]=n1.cube[1][2];
            n2.cube[1][1]=n1.cube[1][3];
            n2.cube[1][0]=n1.cube[1][1];
 
            break;
        }
       
        case 4: //内侧顺时针转一格
        {
            n2.cube[0][2]=n1.cube[2][3];    //上面的2、3块=左面的3、1块
            n2.cube[0][3]=n1.cube[2][1];
 
            n2.cube[2][1]=n1.cube[1][2];    //左面的1、3块=下面的2、3块
            n2.cube[2][3]=n1.cube[1][3];
 
            n2.cube[1][2]=n1.cube[3][3];    //下面的2、3块=右面的3、1块
            n2.cube[1][3]=n1.cube[3][1];
 
            n2.cube[3][1]=n1.cube[0][2];    //右面的1、3块=上面的2、3块
            n2.cube[3][3]=n1.cube[0][3];
 
            n2.cube[4][0]=n1.cube[4][2];    //内侧的4个块顺时针转
            n2.cube[4][2]=n1.cube[4][3];
            n2.cube[4][3]=n1.cube[4][1];
            n2.cube[4][1]=n1.cube[4][0];
 
            break;
        }
        
        case 5: //内侧逆时针转一格
        {
            n2.cube[0][2]=n1.cube[3][1];    //上面的2、3=右面的1、3
            n2.cube[0][3]=n1.cube[3][3];
 
            n2.cube[3][1]=n1.cube[1][3];    //右面的1、3=下面的3、2
            n2.cube[3][3]=n1.cube[1][2];
 
            n2.cube[1][2]=n1.cube[2][1];    //下面的2、3=左面的1、3
            n2.cube[1][3]=n1.cube[2][3];
 
            n2.cube[2][1]=n1.cube[0][3];    //左面的1、3=上面的3、2
            n2.cube[2][3]=n1.cube[0][2];
 
            n2.cube[4][0]=n1.cube[4][1];    //内侧的4个逆时针转
            n2.cube[4][1]=n1.cube[4][3];
            n2.cube[4][3]=n1.cube[4][2];
            n2.cube[4][2]=n1.cube[4][0];
 
            break;
        }
    }

    return(setnum(n2));
}

 

2.推箱子

描述:绝大多数人都玩过推箱子的游戏,控制一个人将箱子推动到目标位置即获得胜利。现请你编写一个程序,判断将箱子推到目标位置至少需要多少步。

输入:推箱子的平面区域为固定大小(10*10),使用10行10列输入推箱子的初始局面。其中,0代表空格,1代表墙,2代表箱子,3代表目标位置,4代表人。
注:游戏中只有一个箱子,一个目标位置,一个人。

输出:

输出将箱子推到目标位置的最小步数;若箱子不可能被推到目标位置,输出-1。

输入样例:

0000000000
0000000300
0100000000
0100000000
0101111100
0000010000
0000010000
0020010040
0000010000
0000010000

输出样例:

34

#include<iostream>
#include<queue>

using namespace std;

char map[10][10];
int used[10][10][10][10] = {0};
int step[10][10][10][10];
int rx, ry, bx, by, tx, ty;

struct game{
	int rrow;
	int rcol;
	int brow;
	int bcol;
};

queue <game> q;

void readdata();
void init();
int bfs();
game rgo(game u, int dir);

int main(){
    readdata();
	init();
	cout << bfs() << endl;
}

void readdata(){
    int i, j;
	for(i = 0; i < 10; i++){
		for(j = 0; j < 10; j++){
		    cin >> map[i][j];
			if(map[i][j] == '4'){
			    rx = i; ry = j;
			}
			if(map[i][j] == '3'){
			    tx = i; ty = j;
			}
			if(map[i][j] == '2'){
			    bx = i; by = j;
			}
		}
	}
}

void init(){
    game u;
	u.rrow = rx;
	u.rcol = ry;
	u.brow = bx;
	u.bcol = by;
	q.push(u);
	used[rx][ry][bx][by] = 1;
	step[rx][ry][bx][by] = 0;
}

int bfs(){
    game u, v;
	while(!q.empty()){
	    u = q.front();
		q.pop();
		if(u.brow == tx && u.bcol == ty){
		    return(step[u.rrow][u.rcol][u.brow][u.bcol]);
		}
		for(int i = 0; i < 4; i++){
		    v = rgo(u, i);
			if(v.rrow < 0 || v.rrow >=10 || v.rcol < 0 || v.rcol >= 10 || map[v.rrow][v.rcol] == '1'){
			    continue;
			}
			else{
				if(!(v.rrow == v.brow && v.rcol == v.bcol) && !used[v.rrow][v.rcol][v.brow][v.bcol]){
				    q.push(v);
					used[v.rrow][v.rcol][v.brow][v.bcol] = 1;
					step[v.rrow][v.rcol][v.brow][v.bcol] = step[u.rrow][u.rcol][u.brow][u.bcol] + 1;
				}
				else if(v.rrow == v.brow && v.rcol == v.bcol){
					if(i == 0 && !used[v.rrow][v.rcol][v.brow][v.bcol+1] && v.bcol<9 && map[v.brow][v.bcol+1] != '1'){
					    v.bcol = v.bcol + 1;
			            q.push(v);
						used[v.rrow][v.rcol][v.brow][v.bcol] = 1;
					    step[v.rrow][v.rcol][v.brow][v.bcol] = step[u.rrow][u.rcol][u.brow][u.bcol] + 1;
					}
					else if(i == 1 && !used[v.rrow][v.rcol][v.brow+1][v.bcol] && v.brow<9 && map[v.brow+1][v.bcol] != '1'){
					    v.brow = v.brow + 1;
						q.push(v);
						used[v.rrow][v.rcol][v.brow][v.bcol] = 1;
					    step[v.rrow][v.rcol][v.brow][v.bcol] = step[u.rrow][u.rcol][u.brow][u.bcol] + 1;
					}
					else if(i == 2 && !used[v.rrow][v.rcol][v.brow][v.bcol-1] && v.bcol>0 && map[v.brow][v.bcol-1] != '1'){
					    v.bcol = v.bcol - 1;
						q.push(v);
						used[v.rrow][v.rcol][v.brow][v.bcol] = 1;
					    step[v.rrow][v.rcol][v.brow][v.bcol] = step[u.rrow][u.rcol][u.brow][u.bcol] + 1;
					}
					else if(i == 3 && !used[v.rrow][v.rcol][v.brow-1][v.bcol] && v.brow>0 && map[v.brow-1][v.bcol] != '1'){
					    v.brow = v.brow - 1 ;
						q.push(v);
						used[v.rrow][v.rcol][v.brow][v.bcol] = 1;
					    step[v.rrow][v.rcol][v.brow][v.bcol] = step[u.rrow][u.rcol][u.brow][u.bcol] + 1;
					}
				}
			}
		}
	}
	return -1;
}

game rgo(game u, int dir){
	int row[4] = {0, 1, 0, -1};
	int col[4] = {1, 0, -1, 0};
	u.rrow += row[dir];
	u.rcol += col[dir];
	return u;
}

 

3.polygon

描述:在一个周长为10000的圆上等距分布着n个点,即这n个点是一个正n边形的顶点。现在要另加m个点到圆上,新加的m个点可以任意选择位置(可以与原有的点重合)。然后将这n+m个点中的一些点延圆周移动,最终使n+m个点均匀分布,即在一个正n+m边形的顶点上。输出最小总移动距离。

输入:输入两个整数 n, m。 (2≤n≤1000, 1≤m≤1000).

输出:输出最小总移动距离,保留4位小数。

输入样例:

sample input #1 2 1

sample input #2 2 3

sample input #3 3 1

sample input #4 10 10

输出样例:

sample output #1 1666.6667

sample output #2 1000.0

sample output #3 1666.6667

sample output #4 0.0

图对应前3个样例

#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;

int main(){
	int n, m;
    double arr1[2000];
	double arr2[2000];
	int i, j;
	double ans, minn;
	while(~scanf("%d%d",&n, &m)){
        
		for(i = 0; i < n; i++){
		    arr1[i] = i*(10000.0/n);
		}
		for(i = 0; i < (m+n); i++){
		    arr2[i] = i*(10000.0/(m+n));
		}
		ans = 0;
		for(i = 0; i < n; i++){
			minn = 10000;
			for(j = 0; j < (m+n); j++){
			    minn = min(minn, fabs(arr1[i]-arr2[j]));
			}
			ans += minn;
		}
		printf("%.4lf\n", ans);
	}
}

 

4.木乃伊迷宫

描述:木乃伊地下宫殿是一个6行6列的迷宫。作为敢到木乃伊地下宫殿里去探险的你,有没有跟木乃伊抓迷藏的心理准备呵!游戏在木乃伊所在的迷宫里展开,任务就是尽快赶到出口。你一次只能走一步,而木乃伊可以走两步,但木乃伊是很笨的,他总是先尽量跟你达到同一列,如果已经是同一列了,他才会像你走来,有墙的地方人和木乃伊都不能过,你可以利用障碍物牵制住木乃伊。

输入:先输入墙的数量n,然后在后续的n行里每行有3个数表示一堵墙,3个数分别为格子的行、列和墙的位置(0表示这个格子的下方是墙,1表示这个格子的右方是墙),再下来的3行每行2个数,分别表示木乃伊、人还有出口的位置。

输出: 如果能安全逃生则输出Yes,否则输出No,答案占一行。

输入样例:

5
0 0 0
1 1 1
1 4 1
3 4 1
4 3 0
3 3
3 1
5 5

输出样例:

No

#include<iostream>
#include<queue>

using namespace std;

int map[6][6] = {0};
int used[6][6][6][6] = {0};
int mx, my, rx, ry, dx, dy;
struct game{
	int rrow;
	int rcol;
	int mrow;
	int mcol;
};
int row[4] = {0, 1, 0 ,-1};
int col[4] = {1, 0, -1, 0};
int flag = 0, flag1;

queue <game> q;

void init();
void dfs();
bool rcanmove(game u, int dir);
game rmove(game u, int dir);
game mmove(game u);
bool getdoor(game u);
bool canto(game u);
bool can(game u);

int main(){
    int n;
	int i;
	int a, b, c; 

	cin >> n;

	for(i = 0; i < n; i++){
	    cin >> a >> b >> c;
		if(c == 1){
		    map[a][b] = 1;
		}
		else{
		    map[a][b] = 2;
		}
	}

	cin >> mx >> my >> rx >>ry >> dx >> dy;
	init();
	dfs();
	if(rx == dx && ry == dy){
	    flag = 1;
	}
	if(!flag){
	    cout << "No" << endl;
	}
	else{
	    cout << "Yes" << endl;
	}
}


void init(){
    game first;

	first.rrow = rx;
	first.rcol = ry;
	first.mrow = mx;
	first.mcol = my;

	q.push(first);
	used[rx][ry][mx][my] = 1;
}

void dfs(){
    game u, v;
	int i;

	while(!q.empty()){
	    u = q.front();
		q.pop();
		for(i = 0; i < 4; i++){
			if(rcanmove(u, i)){ 
			    v = rmove(u, i);
				if(getdoor(v)){
					flag = 1;
				    return;
				}
				if(can(v)){
					flag1 = 0;
					v = mmove(v);
				    if(used[v.rrow][v.rcol][v.mrow][v.mcol] == 0 && !flag1){
						used[v.rrow][v.rcol][v.mrow][v.mcol] = 1;
					    q.push(v); 
				    }
				}
			}
		}
	}
}

bool rcanmove(game u, int dir){
	int nrx, nry;
	nrx = u.rrow;
	nry = u.rcol;

	if(dir == 0){
		if(map[nrx][nry] == 1){
		    return false;
		}
	}
	if(dir == 1){
		if(map[nrx][nry] == 2){
		    return false;
		}
	}
	if(dir == 2){
		if(map[nrx][nry-1] == 1){
			return false;
		}
	}
	if(dir == 3){
		if(map[nrx-1][nry] == 2){
			return false;
		}
	}
	return true;
}

game rmove(game u, int dir){
    game v;

	v.rrow = u.rrow + row[dir];
	v.rcol = u.rcol + col[dir];
	v.mrow = u.mrow;
	v.mcol = u.mcol;

	return v;
}

game mmove(game u){
    int n = 2;
	while(n--){
		if((u.rcol > u.mcol) && (map[u.mrow][u.mcol] != 1)){
		    u.mcol++;
		}
		else{
			if((u.rcol < u.mcol) && (map[u.mrow][u.mcol-1] != 1)){
			    u.mcol--;
			}
			else if(u.rcol == u.mcol){
				if((u.rrow > u.mrow) && (map[u.mrow][u.mcol] != 2)){
				    u.mrow++;
				}
				else if((u.rrow < u.mrow) && (map[u.mrow-1][u.mcol] != 2)){
				    u.mrow--;
				}
				else if(u.rrow == u.mrow && u.rcol == u.mcol){
					flag1 = 1;
					break;
				} 
			}
		}
	}
	return u;
}

bool canto(game u){
	if(u.rrow == u.mrow && u.mcol == u.rcol){
	    return false;
	}
	else{
	    return true;
	}
}

bool getdoor(game u){
	if(u.rrow == dx && u.rcol == dy){
	    return true;
	}
	else{
	    return false;
	}
}

bool can(game u){
	if(u.rrow >= 0 && u.rcol >= 0 && u.rrow < 6 && u.rcol < 6){
	    return true;
	}
	else{
	    return false;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值