1.   营救

铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里。

通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成n*n个比较小的单位,其中用1标明的是陆地,用0标明是海洋。船只能从一个格子,移到相邻的四个格子。

为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。

【输入格式】

第一行为n(0<n<=100),下面是一个n*n的0、1矩阵,表示海洋地图;最后一行为四个小于n的整数,分别表示哥伦比亚号和铁塔尼号的位置。

【输出格式】

哥伦比亚号到铁塔尼号的最短距离。

【样例输入】

3

0 0 1

1 0 1

1 0 0

1 1 3 3

【样例输出】

4

#include <iostream>

using namespace std;
struct node{    
    int x;     
    int y;
    int step;
};
struct node que[10001];      
int map[101][101];   
int book[101][101];  
//int next[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};   
int n,sx,sy,ex,ey,tx,ty,flag = 0;  
int head = 1,tail = 1;
void bfs(){
    int next[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};  
    que[tail].x = sx;
    que[tail].y = sy;
    que[tail].step = 0;
    tail++;
    book[sx][sy] = 1;  
    while(head < tail){
        for(int i = 0;i < 4;i++){
            tx = que[head].x + next[i][0];
            ty = que[head].y + next[i][1];
            if(tx < 1 || tx > n || ty < 1 || ty > n){  
                continue;
            }
            if(map[tx][ty] == 0 && book[tx][ty] == 0){
                book[tx][ty] = 1;
                que[tail].x = tx;
                que[tail].y = ty;
                que[tail].step = que[head].step + 1;
                tail++;                
            }
            if(tx == ex && ty == ey){ 
                flag = 1;
                break;
            }
        }
        if(flag == 1){  
            break;
        }
        head++;  
    }
}
int main(){
    cin >> n;
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= n;j++){
            cin >> map[i][j];
        }
    }
    cin >> sx >> sy >> ex >> ey;
    bfs(); 
    cout << que[tail-1].step << endl; 
    return 0;
}

2、抓住那头牛

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:

1、从X移动到X-1或者X+1,每次移动花费一分钟

2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花费多少时间才能抓住牛?

【输入格式】

两个整数,N和K

【输出样例】

一个整数,农夫抓到牛所要花费的最小分钟数

【样例输入】

5 17

【样例输出】

4

#include <iostream>

using namespace std;
int n,k,x;
bool v[1000001];
int h[1000001][3];
int main(){
    cin >> n >> k;
    h[1][1] = n,v[n] = 1;
    int head = 0,tail = 1;
    do{
        head++;
        for(int i = 1;i <= 3;i++){
            x = h[head][1];
            if(i == 1)
                x++;
            if(i == 2)
                x--;
            if(i == 3)
                x *= 2;
            if(x >= 0 && x <= 100000)
                if(!v[x] || h[x][2] > h[h[head][1]][2]+ 1){
                    tail++;
                    h[tail][1] = x;
                    v[x] = 1;
                    h[x][2] = h[h[head][1]][2]+1;
                }
        }
    }while(head < tail);
    cout << h[k][2] << endl;
    return 0;
}

1、Knight Moves

输入L,代表有L*L的棋盘,输入开始位置的坐标和结束位置的坐标,问一个骑士朝棋盘的八个方向走马字步,从开始坐标到结束坐标可以经过多少步。

【输入格式】

首先输入一个n(0<n<=50),表示测试样例的个数。每个测试样例有三行。第一行是棋盘的大小L(4<=L<=100)。第二行和第三行分别表示马的起始位置和目标位置(0~L-1)。

【输出格式】

马移动的最小步数,起始位置和目标位置相同时输出0。

【样例输入】

3

8

0 0

7 0

100

0 0

30 50

10

1 1

1 1

【样例输出】

5

28

0

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>

using namespace std;
int fx[8] = {1,1,2,2,-1,-1,-2,-2};
int fy[8] = {2,-2,1,-1,2,-2,1,-1};
int N,n,sx,sy,ex,ey,h[5000001][3];
int res[51];
bool visited[1001][1001];
int work(int sx,int sy,int ex,int ey){
    if((sx == ex) && (sy == ey))
        return 0;
    memset(visited,0,sizeof(visited));
//    for(int i = 0;i < 1000;i++){
//        for(int j = 0;j < 1000;j++){
//            visited[i][j] = 0;
//        }
//    }
    int t = 0,w = 1;
    h[1][0] = sx,h[1][1] = sy,h[1][2] = 0;
    do{
        t++;
        int x = h[t][0],y = h[t][1];
        for(int i = 0;i < 8;i++){
            int X = x + fx[i],Y = y + fy[i];
            if(X >= 0 && X < n && Y >= 0 && Y < n && !visited[X][Y]){
                w++;
                h[w][0] = X;
                h[w][1] = Y;
                h[w][2] = h[t][2] + 1;
                visited[X][Y] = 1;
                if(X == ex && Y == ey)
                    return h[w][2];
            }
        }
    }while(t < w);
}
int main(){
    cin >> N;
    for(int i = 1;i <= N;i++){
        cin >> n >> sx >> sy >> ex >> ey;
        res[i] = work(sx,sy,ex,ey);
    }
    for(int j = 1;j <= N;j++){
        cout <<res[j] << endl;
    }
    return 0;
}

2. Lake Counting

有一块N*M(1<=N,M<=100)的土地,雨后积起了水,有水标记为‘$’,干燥为‘#’。八连通的积水被认为是连接在一起的。请求出院子里共有多少水洼?(八连通区域指的是从区域内每一位置出发,可通过八个方向,即上、下、左、右、左上、右上、左下、右下这八个方向的移动的组合,在不越出区域的前提下,到达区域内的任意位置。)

【样例输入】

10 12

$########$$#

#$$$#####$$$

####$$###$$#

#########$$#

#########$##

##$######$##

#$#$#####$$#

$#$#$####$$#

#$#$######$#

##$#######$#

【样例输出】

3

#include <iostream>
using namespace std;
struct node {
    int x;
    int y;
};
char map[51][51];
struct node que[2501];
int head,tail;
int book[51][51];
int sum;
int next[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},{1,1},{1,-1},{-1,-1}};//右下左上
int m,n,x,y,tx,ty;

void bfs(int x,int y) {
    sum++;
    map[x][y] = 0; 
    //初始化队列
    head = 1;
    tail = 1;
    que[tail].x = x;
    que[tail].y = y;
    book[x][y] = 1;
    tail++;
    while(head < tail) {
        for(int k = 0; k < 8; k++) {
            tx = que[head].x + next[k][0];
            ty = que[head].y + next[k][1];
            if(tx < 0 || tx >= m || ty < 0 || ty >= n) {
                continue;
            }
            if(map[tx][ty] == '$' && book[tx][ty] == 0) {
                map[tx][ty] = '#';
                book[tx][ty] = 1;
                que[tail].x = tx;
                que[tail].y = ty;
                tail++;
            }
        }
        head++;
    }
}
int main() {
    cin >> m>>n;
    for(int i = 0; i <m; i++) {
        for(int j = 0; j < n; j++) {
            cin >> map[i][j];
        }
    }
    for(int i = 0; i <m; i++) {
        for(int j = 0; j < n; j++) {
            if(map[i][j] == '$') {
                bfs(i,j);
            }
        }
    }
    cout <<sum << endl;
    return 0;
}

3、迷宫问题

定义一个二维数组:

int maze[5][5] = {

  0, 1, 0, 0, 0,

  0, 1, 0, 1, 0,

  0, 0, 0, 0, 0,

  0, 1, 1, 1, 0,

  0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

【输入格式】

一个5 * 5的二维数组,表示一个迷宫。数据保证有唯一解。

【输出格式】

左上角到右下角的最短路径,格式如样例所示。

【样例输入】

0 1 0 0 0

0 1 0 1 0

0 0 0 0 0

0 1 1 1 0

0 0 0 1 0

【样例输出】

(0,0)

(1,0)

(2,0)

(2,1)

(2,2)

(2,3)

(2 , 4)

(3 , 4)

(4,4)

#include <iostream>

using namespace std;
int h[37][3],b[26];
int xx[4] = {-1,1,0,0},yy[4] = {0,0,-1,1};
bool a[6][6];
int main(){
    int t = 0,w = 1,x,y,k = 0;
    for(int i = 0;i < 5;i++){
        for(int j = 0;j < 5;j++){
            cin >> a[i][j];
        }
    }
    h[1][1] = 0;
    h[1][2] = 0;
    a[1][1] = 1;
    do{
        t++;
        for(int i =0;i < 4;i++){
            x = h[t][1] + xx[i];
            y = h[t][2] + yy[i];
            if(x >= 0 && x < 5 && y >= 0 && y < 5 && a[x][y] == 0){
                a[x][y] = 1;
                w++;
                h[w][0] = t;
                h[w][1] = x;
                h[w][2] = y;
                if(x == 4 && y == 4)
                    break;
            }
        }
        
    }while(t < w);
    while(w > 1){
        k++;
        b[k] = w;
        w = h[w][0];
    }
    cout << "(0,0)" << endl;
    for(int i = k;i >= 1;i--)
        cout << "(" << h[b[i]][1] << "," << h[b[i]][2] << ")" << endl;
    return 0;
}