10.9-分支界限法(//跳馬//獨輪車//六數碼問題//找倍數//八數碼問題)
阿新 • • 發佈:2018-12-30
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;
}