10.9-分支界限法(//跳马//独轮车//六数码问题//找倍数//八数码问题)

1.跳马

描述:在国际象棋中,马的走法与中车象棋类似,即俗话说的“马走日”,下图所示即国际象棋中马(K)在一步能到达的格子(其中黑色的格子是能到达的位置)。

现有一200*200大小的国际象棋棋盘,棋盘中仅有一个马,给定马的当前位置(S)和目标位置(T),求出马最少需要多少跳才能从当前位置到达目标位置。

输入:本题包含多个测例。输入数据的第一行有一个整数N(1<=N<=1000),表示测例的个数,接下来的每一行有四个以空格分隔的整数,分别表示马当前位置及目标位置的横、纵坐标C(x,y)和G(x,y)。坐标由1开始。

输出:对于每个测例,在单独的一行内输出一个整数,即马从当前位置跳到目标位置最少的跳数。

输入样例

2
1 1 2 1
1 5 5 1

输出样例

3
4

#include<iostream>
#include<queue>
 
using namespace std;
 
int cx,cy,gx,gy;
int a[201][201]={0};
int step[201][201];
//马走的方向所对应的行列变化 
int b[8]={-2,-2,-1,-1,1,1,2,2};
int c[8]={-1,1,-2,2,-2,2,-1,1};
 
//结构体内定义队列 
struct add
{
 queue<int>q1;
 queue<int>q2;
}add;
 
int search(int x,int y);
 
int main()
{
 int n,i,j,k=0;
 cin>>n;
 int ans[n];
 while(k<n)
 {
  cin>>cx>>cy>>gx>>gy;
  //初始化 
  step[cx][cy]=0;
  a[cx][cy]=1;
  add.q1.push(cx);
  add.q2.push(cy);
  ans[k++]=search(cx,cy);
  //清空棋盘和队列,防止下一组测试受到影响 
  for(i=0;i<201;i++)
     {
      for(j=0;j<201;j++)
      {
       a[i][j]=0;
       step[i][j]=0; 
      }
     }
     while(!add.q1.empty())
     {
      add.q1.pop();
     }
     while(!add.q2.empty())
        {
      add.q2.pop();
     }
 }
 for(i=0;i<n;i++)
 {
  cout<<ans[i]<<endl;
 } 
 return 0;
}
 
int search(int x,int y)
{
 int xt,yt,e,f,i;
 while(1)
 {
  e=add.q1.front();
  add.q1.pop();
  f=add.q2.front();
     add.q2.pop();
  for(i=0;i<8;i++)
     {
       xt=e+b[i];
      yt=f+c[i];
      if(xt==gx&&yt==gy)
      {
        return(step[e][f]+1);
      }
      if(xt<1||xt>200||yt<1||yt>200) continue;//剪枝数组越界的情况 
      if(a[xt][yt]==0)
      {//处理下一组可能的情况 
       a[xt][yt]=1;
       step[xt][yt]=step[e][f]+1;
       add.q1.push(xt);
       add.q2.push(yt);
      }
     }
 }
}

 

2.独轮车

描述:独轮车的轮子上有红、黄、蓝、白、绿(依顺时针序)5种颜色,在一个如下图所示的20*20的迷宫内每走一个格子,轮子上的颜色变化一次。独轮车只能向前推或在原地转向。每走一格或原地转向90度均消耗一个单位时间。现给定一个起点(S)和一个终点(T),求独轮车以轮子上的指定颜色到达终点所需的最短时间。

 

输入:本题包含一个测例。测例中分别用一个大写字母表示方向和轮子的颜色,其对应关系为:E-东、S-南、W-西、N-北;R-红、Y-黄、B-蓝、W-白、G-绿。在测试数据的第一行有以空格分隔的两个整数和两个大写字母,分别表示起点的坐标S(x,y)、轮子的颜色和开始的方向,第二行有以空格分隔的两个整数和一个大写字母,表示终点的坐标T(x,y)和到达终点时轮子的颜色,从第三行开始的20行每行内包含20个字符,表示迷宫的状态。其中'X'表示建筑物,'.'表示路.

输出:在单独的一行内输出一个整数,即满足题目要求的最短时间。

输入样例

3 4 R N
15 17 Y
XXXXXXXXXXXXXXXXXXXX
X.X...XXXXXX......XX
X.X.X.....X..XXXX..X
X.XXXXXXX.XXXXXXXX.X
X.X.XX....X........X
X...XXXXX.X.XX.X.XXX
X.X.XX....X.X..X.X.X
X.X.X..XX...XXXX.XXX
X.X.XX.XX.X....X.X.X
X.X....XX.X.XX.X.X.X
X.X.X.XXXXX.XX.X.XXX
X.X.X.XXXXX....X...X
X.X.......X.XX...X.X
X.XXX.XXX.X.XXXXXXXX
X.....XX.......X...X
XXXXX....X.XXXXXXX.X
X..XXXXXXX.XXX.XXX.X
X.XX...........X...X
X..X.XXXX.XXXX...XXX
XXXXXXXXXXXXXXXXXXXX

输出样例

56

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

char map[20][20];
bool canuse[20][20][5][6];
int step[20][20][5][6];
int tx, ty, tcolor;
int ans;
int gorow[4] = {-1, 0, 1, 0};
int gocol[4] = {0, 1, 0, -1};

struct horse{
	queue <int> row;
	queue <int> col;
	queue <int> dire;
	queue <int> color;
}horse;

void init();
int search();
int change(char c);

int main(){
    init();
	ans = search();
	cout << ans <<endl;
	return 0;
}

void init(){
	int i, j, k, l;
	int cx, cy;
    char cdir;
    char ccol;
    char tcol;
    cin >> cx >> cy >> ccol >> cdir;
	cin >> tx >> ty >> tcol;
	for(i = 0; i < 20; i++){
		for(j = 0; j < 20; j++){
		    cin >> map[i][j];
			if(map[i][j] == 'X'){
				for(k = 0; k < 4; k++){
					for(l = 0; l < 5; l++){
					    canuse[i][j][k][l] = false;
					}
				}
			}
			else{
				for(k = 0; k < 4; k++){
					for(l = 0; l < 5; l++){
                        canuse[i][j][k][l] = true;
					}
				}
			}
		}
	}
	tcolor = change(tcol);
	step[cx-1][cy-1][change(cdir)][change(ccol)] = 0;
	horse.row.push(cx-1);
	horse.col.push(cy-1);
	horse.dire.push(change(cdir));
	horse.color.push(change(ccol));
	canuse[cx-1][cy-1][change(cdir)][change(ccol)] = false; 
}

int change(char c){
	if(c == 'N') return 0;
	if(c == 'E') return 1;
	if(c == 'S') return 2;
	if(c == 'W') return 3;
	if(c == 'R') return 0;
	if(c == 'Y') return 1;
	if(c == 'B') return 2;
	if(c == 'W') return 3;
	if(c == 'G') return 4;
}

int search(){
	int nx, ny, vx, vy;
	int ndire, ncolor, vdire, vcolor;
	int i;
	while(1){
	    nx = horse.row.front();
		ny = horse.col.front();
		ndire = horse.dire.front();
		ncolor = horse.color.front();
		horse.row.pop();
		horse.col.pop();
		horse.dire.pop();
		horse.color.pop();
		for(i = 0; i < 3; i++){  //0表示顺时针转向,1表示逆时针转向,2表示向前走一步
			if(i == 0){
			    vcolor = ncolor;
				vdire = (ndire+1)%4;
				vx = nx;
				vy = ny;
			}
			else if(i == 1){
			    vcolor = ncolor;
				vdire = (ndire+3)%4;
				vx = nx;
				vy = ny;
			}
			else{
                vcolor = (ncolor+1)%5;
				vdire = ndire;
				vx =nx + gorow[ndire];
				vy =ny + gocol[ndire];
			}
           if(vx == tx-1 && vy == ty-1 && vcolor == tcolor){
		        return(step[nx][ny][ndire][ncolor] + 1);
		   }
		   if(vx >= 0 && vx < 20 && vy >= 0 && vy < 20 && canuse[vx][vy][vdire][vcolor]){
		       horse.row.push(vx);
			   horse.col.push(vy);
			   horse.dire.push(vdire);
			   horse.color.push(vcolor);
			   canuse[vx][vy][vdire][vcolor] = false;
			   step[vx][vy][vdire][vcolor] = step[nx][ny][ndire][ncolor] + 1; 
		   }
		}	
	}
}

 

 

3.六数码问题

描述:现有一两行三列的表格如下:

A B C
D E F

把1、2、3、4、5、6六个数字分别填入A、B、C、D、E、F格子中,每个格子一个数字且各不相同。每种不同的填法称为一种布局。如下:

1 3 5
2 4 6
布局1

2 5 6
4 3 1
布局2

定义α变换如下:把A格中的数字放入B格,把B格中的数字放入E格,把E格中的数字放入D格,把D格中的数字放入A格。
定义β变换如下:把B格中的数字放入C格,把C格中的数字放入F格,把F格中的数字放入E格,把E格中的数字放入B格。

问:对于给定的布局,可否通过有限次的α变换和β变换变成下面的目标布局:

1 2 3
4 5 6
输入:本题有多个测例,每行一个,以EOF为输入结束标志。每个测例的输入是1到6这六个数字的一个排列,空格隔开,表示初始布局ABCDEF格中依次填入的数字。

输出:每个输出占一行。可以转换的,打印Yes;不可以转换的,打印No。

输入样例

1 3 5 2 4 6
2 5 6 4 3 1

输出样例

No
Yes

提示:第二个示例即布局2的一种转换方法:αααβαα

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

queue <int> q;
map <int, int> used;

int pow(int x, int y);
int bfs();
int moveto(int v, int i);

int main(){
	int num, tmp;
	while(cin >> tmp){
		num = tmp*pow(10,5);
		for(int i = 4; i >= 0; i--){
		    cin >> tmp;
			num += tmp*pow(10,i); 
		}

		while(!q.empty()){
		    q.pop();
		}
		used.clear();

		q.push(num);
		used[num] = 1;

		if(bfs()){
		    cout << "Yes" <<endl;
		}
		else{
		    cout << "No" <<endl;
		}
	}
}

int bfs(){
	int u, v;
	while(!q.empty()){
	    u = q.front();
		q.pop();
		for(int i = 0; i < 2; i++){    //i==0做α变换,i==1做 β变换 
		    v = moveto(u, i);
            if(u == 123456){
		        return 1;
		    }
			if(used[v] == 0){
			    q.push(v);
				used[v] = 1;
			}
		}
	}
	return 0;
}

int pow(int x, int y){
	int num;
	num = x; 
	if(y == 0){
		return 1;
	}
	for(int i = 0; i < y-1; i++){
	    num *= x;
	} 
	return num;
}

int moveto(int v, int i){
	int a, b, c, d, e, f, tmp;
	f = v%10; v = v/10;
	e = v%10; v = v/10;
	d = v%10; v = v/10;
	c = v%10; v = v/10;
	b = v%10; v = v/10;
	a = v%10;
	if(i == 0){
	    tmp = a;
		a = d;
		d = e;
		e = b;
		b = tmp;
	}
	else{
	    tmp = b;
		b = e;
		e = f;
		f = c;
		c = tmp;
	}
	for(int i = 0; i < 6; i++){
	    return(a*pow(10,5)+b*pow(10,4)+c*pow(10,3)+d*pow(10,2)+e*pow(10,1)+f);
	}
}

 

 

4.找倍数

描述:对于每个输入的数字(如:2),则要求 给出一个由1,0构成的十进制整数,且该整数为输入数字的某个倍数,且是满足该条件的最小数(如2对应的10)。

输入:数字n,n等于0时停止。

输出:n的一个满足条件的最小倍数。

输入样例

2
0

输出样例

10

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

long long n;

queue <long long> q;

void search();

int main(){
	while(cin >> n && n != 0){
		if(n == 1){
		    cout << '1' << endl;
		}
		else{
		    while(!q.empty()){
		        q.pop();
		    }
		    q.push(1);
		    search();
		}
	}
	return 0;
}

void search(){
    long long u, v;
	int flag = 0;
	while(!q.empty()){
		if(flag){
		    break;
		}
	    u = q.front();
	    q.pop();
		for(int i = 0; i < 2; i++){
		    v = u*10 + i;
			if(v % n == 0){
			    cout << v << endl;
				flag = 1;
				break;
			}
			else{
			    q.push(v);
			}
		}
	}
}

 

 

5.八数码问题

描述:在九宫格里放在1到8共8个数字还有一个是空格,与空格相邻的数字可以移动到空格的位置,问给定的状态最少需要几步能到达目标状态(用0表示空格):
1 2 3
4 5 6
7 8 0

输入:输入一个给定的状态。

输出:输出到达目标状态的最小步数。不能到达时输出-1。

输入样例:

1 2 3
4 0 6
7 5 8

输出样例:

2

#include<iostream>
#include<queue>
#include<map>

using namespace std;

queue <int> q;
map <int, int> step;
map <int, int> used;

void init();
int bfs();
bool canmove(int u, int i);
int move(int u, int i);

int tx[4] = {0, 1, 0, -1};
int ty[4] = {1, 0, -1, 0};

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

void init(){
    int i;
	int tmp, num;
	cin >> tmp;
	num = tmp;
	for(i = 0; i < 8; i++){
	    cin >> tmp;
		num = num*10 + tmp;
	}
	step.clear();
	used.clear();
	q.push(num);
	step[num] = 0;
	used[num] = 1;
}

int bfs(){
	int i;
    int u, v;
	u = q.front();
	if(u == 123456780){
	    return 0;
	}
	while(!q.empty()){
	    u = q.front();
		q.pop();
		for(i = 0; i < 4; i++){  //分别向右,下,左,上交换
			if(canmove(u, i)){
			    v = move(u, i);
				if(v == 123456780){
				    return(step[u] + 1);
				}
				if(used.count(v) == 0){
				    q.push(v);
					step[v] = step[u] + 1;
					used[v] = 1;
				}
			}
		}
	}
	return -1;
}

bool canmove(int u, int i){
    int arr[3][3];
	int  j, k;
	int row, col;
	int vx, vy;
	for(j = 2; j >= 0; j--){
		for(k = 2; k >= 0; k--){
		    arr[j][k] = u%10;
			u = u/10;
			if(arr[j][k] == 0){
			    row = j;
				col = k;
			}
		}
	}
	vx = row + tx[i];
	vy = col + ty[i];
	if(vx >= 0 && vx < 3 && vy >= 0 && vy < 3){
	    return true;
	}
	else{
	    return false;
	}
}

int move(int u, int i){
    int arr[3][3];
	int j, k;
	int row, col;
	int vx, vy;
	int num;
	for(j = 2; j >= 0; j--){
		for(k = 2; k >= 0; k--){
		    arr[j][k] = u%10;
			u = u/10;
			if(arr[j][k] == 0){
			    row = j;
				col = k;
			}
		}
	}
	vx = row + tx[i];
	vy = col + ty[i];
	arr[row][col] = arr[vx][vy];
	arr[vx][vy] = 0;
	num = 0;
	for(j = 0; j < 3; j++){
		for(k = 0; k < 3; k++){
		    num = num*10 + arr[j][k];
		}
	}
	return num;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值