中学信息奥赛

 中学信息奥赛基础第6章广度优先搜索课堂练习

1.数塔问题

题目描述

在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

输入格式

输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。

输出格式

对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。

样例输入 

1
5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5

样例输出 

30

源代码

#include<bits/stdc++.h>
using namespace std;

struct node{
	int x,y,value;
}que[10005];
int rear=0,front=0;
int a[105][105];
int lastlevel,maxv;

void bfs(int x,int y){
	struct node p,q;
	p.x=x;
	p.y=y;
	p.value=a[x][y];
	que[rear++]=p;
	while(rear!=front){
		q=que[front++];
		if(q.x==lastlevel){
			if(maxv<q.value) maxv=q.value;
		}else{
			p.x=q.x+1;
			p.y=q.y;
			p.value=q.value+a[q.x+1][q.y];
			que[rear++]=p;
			p.x=q.x+1;
			p.y=q.y+1;
			p.value=q.value+a[q.x+1][q.y+1];
			que[rear++]=p;
		}
	}
}

int main(){
	int n,m;
	cin>>n;
	while(n--){
		cin>>m;
		for(int i=0;i<m;i++){
			for(int j=0;j<=i;j++)cin>>a[i][j];
		}
		lastlevel=m-1;
		maxv=0;
		bfs(0,0);
		cout<<maxv<<endl;
	}
	return 0;
}

2.细胞

题目描述

一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如:

阵列

4 10

0234500067

1034560500

2045600671

0000000089

有4个细胞。

输入格式

第一行为矩阵的行n和列m;

下面为一个n×m的矩阵。

输出格式

细胞个数。

样例输入 #1

4 10
0234500067
1034560500
2045600671
0000000089

样例输出 #1

4

源代码

#include<bits/stdc++.h>
using namespace std;
int dx[4]={-1, 0, 1, 0},  dy[4]={0, 1, 0, -1};    
int cell[100][100], num=0, n, m;  
void bfs(int x,int y)
{  int new_x, new_y, i;
   int queue[1000][3], head=0, tail=0;    
   cell[x][y]=0;
   queue[tail][1]=x;   queue[tail][2]=y;   tail++;    
   while(head<tail)     
    {  x = queue[head][1];  y = queue[head][2];   
       head++;   
       for (i=0;i<=3;i++)                      
      { new_x = x+dx[i];     new_y = y+dy[i];
        if ((new_x>=0)&&(new_x<m)&&(new_y>=0)&&(new_y<n)&&(cell[new_x][new_y])) 
         {      queue[tail][1]=new_x;                   
                 queue[tail][2]=new_y; 
                 tail++ ;
                cell[new_x][new_y]=0;  
         }                                          
      }
    }                             
}

int main()
{
   int i,j; 
   char s[100],ch;
   scanf("%d%d\n",&m,&n);
   for (i=0;i<m;i++)
    {   gets(s); 
        for (j=0; j<n; j++)    cell[i][j]=s[j]-'0';
    }
   for (i=0; i<m; i++)
      for (j=0; j<n; j++)
          if (cell[i][j])  
           {
               num++;      
               bfs(i, j);   
            }
   printf("%d\n",num);
   return 0;
} 

3.最小步数

题目描述

在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100×100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。

输入格式

A、B两点的坐标。

输出格式

最少步数。

样例输入 #1

12 16
18 10

样例输出 #1

8
9
 

源代码

#include<bits/stdc++.h>
using namespace std;

int dx[12]={-2,-2,-1,1,2,2,2,2,1,-1,-2,-2};
int dy[12]={-1,-2,-2,-2,-2,-1,1,2,2,2,2,1};

int main(){
	int s[101][101],x1,y1,x2,y2,steps;
	int x,y,new_x,new_y;
	int que[10000][4]={0},head=0,tail=0;
	cin>>x1>>y1>>x2>>y2;
	memset(s,0xff,sizeof(s));
	que[tail][1]=1;
	que[tail][2]=1;
	que[tail][3]=0;
	tail++;
	while(head<tail){
		x=que[head][1];
		y=que[head][2];
		steps=que[head][3];
		head++;
		for(int d=0;d<=11;d++){
			new_x=x+dx[d];
			new_y=y+dy[d];
			if(new_x>0&&new_x<=100&&new_y>0&new_y<=100){
				if(s[new_x][new_y]==-1){
					que[tail][1]=new_x;
					que[tail][2]=new_y;
					que[tail][3]=steps+1;
					tail++;
					s[new_x][new_y]=steps+1;
					if(s[x1][y1]>0&&s[x2][y2]>0){
						cout<<s[x1][y1]<<endl;
						cout<<s[x2][y2]<<endl;
						return 0;
					}
				}	
			}
		}
	}
}

4.迷宫

题目描述

小 C 最近在研究机器人,他想看看自己的机器人够不够智能,于是他将机器人放在一个 n×mn×m 的迷宫中,看看机器人能不能在最短的时间内到达目的地,可是小 C 不知道最短的时间是多少,现在请你帮他算算机器人到达目的地的最短时间是多少?

输入格式

输入数据第一行两个整数 n,m (1≤n,m≤420)n,m (1≤n,m≤420)。

接下来 nn 行,每行 mm 个元素,表示迷宫的每个方格。

  • S 表示机器人的出发点,
  • T 表示目的地,
  • # 表示该方格不能通过,
  • . 表示可以通过。

输出格式

输出一个整数表示机器人到达目的地的最短时间。

如果机器人不能到达目的地,输出 -1

样例输入 #1

3 3
S..
##.
.T.

样例输出 #1

5

源代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
int dir[2][4]={{1,-1,0,0},{0,0,1,-1}};
int dis[510][510];
char mp[510][510];
queue<pair<int,int> >q;  

void bfs(int i,int j)
{
     q.push({i,j}); 
     while(!q.empty()){
	int x,y;  
                x = q.front().first; y = q.front().second;
	q.pop();
	for(int i=0; i<4; ++i){
	     int xx=x+dir[0][i], yy=y+dir[1][i];
	     if(0<=xx&&xx<n&&0<=yy&&yy<m&&dis[xx][yy]==-1){
		if(mp[xx][yy]=='.'){
		     dis[xx][yy]=dis[x][y]+1;
		     q.push( {xx,yy} );
		}
		else if(mp[xx][yy]=='T'){
		     cout<<dis[x][y]+1<<'\n';
		     return;
		}
	     }
	}
     }
     cout<<"-1\n";
}
int main()
{
     memset(dis,-1,sizeof dis);
     cin>>n>>m;
     for(int i=0;i<n;++i)
       cin>>mp[i];
     for(int i=0;i<n;++i)
       for(int j=0;j<m;++j)
       {
     	if(mp[i][j]=='S')
	{ 
 	      dis[i][j]=0;     bfs(i,j);
	}
       }
     return 0;
}

5.走迷宫

题目描述

一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。

给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。

输入格式

第一行是两个整数,R和C,代表迷宫的长和宽。( 1≤ R,C ≤ 40)

接下来是R行,每行C个字符,代表整个迷宫。

空地格子用‘.’表示,有障碍物的格子用‘#’表示。

迷宫左上角和右下角都是‘.’。

输出格式

输出从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。计算步数要包括起点和终点。

样例输入 #1

5 5
..###
#....
#.#.#
#.#.#
#.#..

样例输出 #1

9

源代码

#include<bits/stdc++.h>
using namespace std;

int minSteps(const vector<string>& maze, pair<int, int> start, pair<int, int> end) {
    vector<pair<int, int> > directions;
    directions.push_back(make_pair(-1, 0));
    directions.push_back(make_pair(1, 0));
    directions.push_back(make_pair(0, -1));
    directions.push_back(make_pair(0, 1));

    queue<pair<int, int> > q;
    map<pair<int, int>, int> steps;

    q.push(start);
    steps[start] = 1;

    while (!q.empty()) {
        pair<int, int> current = q.front();
        q.pop();
        if (current == end) {
            return steps[end];
        }

        for (int i = 0; i < directions.size(); ++i) {
            int nx = current.first + directions[i].first;
            int ny = current.second + directions[i].second;
            if (nx >= 0 && nx < maze.size() && ny >= 0 && ny < maze[0].size() && maze[nx][ny] == '.' && !steps.count(make_pair(nx, ny))) {
                q.push(make_pair(nx, ny));
                steps[make_pair(nx, ny)] = steps[current] + 1;
            }
        }
    }

    return -1; 
}

int main() {
    int R, C;
    cin >> R >> C;
    vector<string> maze(R);
    for (int i = 0; i < R; ++i) {
        cin >> maze[i];
    }

    pair<int, int> start = make_pair(0, 0);
    pair<int, int> end = make_pair(R - 1, C - 1);

    int result = minSteps(maze, start, end);
    cout << result << endl;

    return 0;
}

6.抓住那头牛

题目描述

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

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

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

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

输入格式

两个整数,N和K。

输出格式

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

样例输入 #1

5 17

样例输出 #1

4
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
queue<int>que;
int cow[100005];//用于标记是否走过了,并标记走到目前这里花了多少步
int step[3];//三种走法
int n,k;
void bfs()
{
    que.push(n);//农夫进队
    memset(cow,-1,sizeof(cow));
    cow[n]=0;
    while(!que.empty())
    {
        int cur=que.front();
        que.pop();
        if(cur==k)break;//已经抓到牛了
        //三种移动方式
        step[0]=cur-1;
        step[1]=cur+1;
        step[2]=cur*2;
        for(int i=0;i<3;i++)
        {
            if(step[i]>=0&&step[i]<100001&&cow[step[i]]==-1)
            {
                que.push(step[i]);
                cow[step[i]]=cow[cur]+1;//进行标记
            }
        }

    }
    cout<<cow[k]<<endl;
}
int main()
{

   cin>>n>>k;
   bfs();
   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值