目录
题目 A: 城堡
题目描述
某城堡被分割成 m×n(m ≤ 50,n ≤ 50)个方块,每个方块的四面可能有墙,“#”代表有墙,没有墙分割的方块连在一起组成一个房间,城堡外围一圈都是墙。如果 1、2、4 和 8 分别对应左墙、上墙、右墙和下墙,则可以用方块周围每个墙对应的数字之和来描述该方块四面墙的情况,请计算城堡一共有多少个房间,最大的房间有多少个方块。
给定m×n数字矩阵,其每个数字都是0~15中的一个数字,求解本问题。
输入
有多组测试数据。每组第一行是2个整数m,n。接着有m行,每行有n个用空格隔开的正整数aij,aij都是0~15中的一个数字。
输出
对每组测试数据,一行上输出2个整数:房间个数roomNum,最大房间的方块数maxRoom。
样例输入
3 5
11 6 11 6 7
7 9 6 9 12
9 10 12 11 14
样例输出
3 8
参考答案:
这个写成类的纯粹突发奇想折磨自己玩的hhhhhh 不用写成类,全局变量挺好的hhhhh
#include<iostream>
#include<vector>
class Castle
{
public:
std::vector<std::vector<int>> visited_castle; // 已遍历地图
std::vector<std::vector<int>> map_castle; // 城堡地图
int roomNum = 0; // 房间个数
int roomArea = 0; // 房间大小
int maxRoom = 0; // 最大房间大小
// 初始化城堡
std::vector<std::vector<int>> Map_Initialize(int row, int column)
{
std::vector<std::vector<int>> map_castle(row, std::vector<int>(column, 0));
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
std::cin >> map_castle[i][j];
}
}
return map_castle;
}
// 城堡问题解决方案
void Castle_solution(std::vector<std::vector<int>> map_castle)
{
for (int i = 0; i < map_castle.size(); i++)
{
for (int j = 0; j < map_castle[0].size(); j++)
{
if (visited_castle[i][j] == 0)
{
roomNum++;
roomArea = 0;
DFS(i,j);
if (roomArea > maxRoom)
{
maxRoom = roomArea;
}
}
}
}
std::cout<< roomNum <<" " << maxRoom << "\n";
}
// 深搜
void DFS(int i, int j)
{
if(visited_castle[i][j] == 1) return;
roomArea++;
visited_castle[i][j] =1;
if(i>=0 && j<map_castle[0].size())
{
if( (map_castle[i][j] & 1) == 0) DFS(i,j-1);
if( (map_castle[i][j] & 2) == 0) DFS(i-1,j);
if( (map_castle[i][j] & 4) == 0) DFS(i,j+1);
if( (map_castle[i][j] & 8) == 0) DFS(i+1,j);
}
}
// 生成城堡
Castle(int row, int column)
{
map_castle = Map_Initialize(row,column);
std::vector<std::vector<int >> temp (row,std::vector<int>(column,0));
visited_castle = temp;
}
};
int main()
{
int row,column;
while(std::cin >> row >> column)
{
Castle castle = Castle(row,column);
castle.Castle_solution(castle.map_castle);
}
return 0;
}
题目 B: 山洞寻宝图
题目描述
在一座山上有 n 个山洞,其中有一个山洞藏有寻宝图,有个猎人知道山上有寻宝图但不知道藏在哪个山洞里,只要猎人到达寻宝图所在的山洞就一定能够得到藏宝图。假设猎人熟悉山路,但是有些山洞之间没有山路相通。
给定 n(3 ≤ n ≤ 100)个山洞之间的连通关系、寻宝图所在山洞、以及猎人寻找的起始山洞,请问猎人是否能够得到寻宝图?
输入
有多组测试数据。每组的第一行是3个整数 n,u,v(3 ≤ n ≤ 100,0≤ u,v ≤ n-1)。
接着,是n行每行是由0、1表示的n个数,其中第i行的第j列的1表示山洞i与山洞j相连,0表示不相连。
特别提醒:顶点变换是0~n-1.
输出
对每组测试数据,请问在山洞u的猎人是否能够得到山洞v处的寻宝图,如能找到,则输出Yes,否则输出No。
样例输入
6
1 2
0 0 1 0 0 0
0 0 1 0 0 0
1 1 0 0 0 1
0 0 0 0 1 0
0 0 0 1 0 0
0 0 1 0 0 0
6
1 4
0 0 1 0 0 0
0 0 1 0 0 0
1 1 0 0 0 1
0 0 0 0 1 0
0 0 0 1 0 0
0 0 1 0 0 0
样例输出
Yes
No
提示
注意初始化数组和变量
参考答案:
#include<iostream>
#include<vector>
/// @brief 深搜
/// @param Cave_map 引用形式,防止超时
/// @param u 猎人当前山洞
/// @param v 宝藏所在山洞
/// @param isfind 是否找到宝藏
void DFS(std::vector<std::vector<int >>& Cave_map,int u,int v,bool& isfind)
{
if(isfind == true) return;
if (u == v)
{
isfind = true;
}
for(int i = 0;i<Cave_map.size();i++) // 进入所有连通山洞
{
if(Cave_map[u][i]==1)
{
Cave_map[u][i] = 0; // 关闭退路
Cave_map[i][u] = 0; // 走过之后要设置为不连通,以防来回走导致死循环
DFS(Cave_map,i,v,isfind);
}
}
}
int main()
{
int n; // n个山洞
int u , v; // 猎人所在的山洞,宝藏所在的山洞
while(std::cin >> n >> u >> v)
{
bool isfind = false;
// 山洞间的连通关系
std::vector<std::vector<int >> Cave_map (n,std::vector<int >(n,0));
for(int i = 0;i < n; i++)
{
for(int j = 0; j < n ; j++ )
{
std::cin >> Cave_map[i][j];
}
}
DFS(Cave_map,u,v,isfind);
if(isfind == true)
{
std::cout<<"Yes\n";
}
else
{
std::cout<<"No\n";
}
}
return 0;
}
题目 C: 迷宫
题目描述
小明置身于一个迷宫,请你帮小明找出从起点到终点的最短路程。
小明只能向上下左右四个方向移动。
输入
输入包含多组测试数据。输入的第一行是一个整数T,表示有T组测试数据。
每组输入的第一行是两个整数N和M(1<=N,M<=100)。
接下来N行,每行输入M个字符,每个字符表示迷宫中的一个小方格。
字符的含义如下:
‘S’:起点
‘E’:终点
‘-’:空地,可以通过
‘#’:障碍,无法通过
输入数据保证有且仅有一个起点和终点。
输出
对于每组输入,输出从起点到终点的最短路程,如果不存在从起点到终点的路,则输出-1。
样例输入
1
5 5
S-###
-----
##---
E#---
---##
样例输出
9
参考答案:
#include<iostream>
#include<vector>
int start_position[2];//开始坐标,行,列
int end_position[2];//结束坐标,行,列
// 行列 :上,右,下,左
//int move_xy[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
int move_x[4] = {-1,0,1,0};
int move_y[4] = {0,-1,0,1};
int min_step ; // 最小步数
bool isFind ; // 是否找到
void DFS(std::vector<std::vector<char >>& map,std::vector<std::vector<int >>& visited_map,int current_row,int current_column,int step)
{
if(map[current_row][current_column]=='E') // 终点判断
{
min_step = std::min(step,min_step); // 更新最小值
isFind = true; // 已经找到
return ;
}
for(int i = 0;i<4;i++) // 往四个方向深搜
{
int temp_x = current_row + move_x[i];
int temp_y = current_column + move_y[i];
//边界判断
if(temp_x <0 || temp_x >= map.size() || temp_y <0 || temp_y >= map[0].size() ) continue;
// 非墙且此时的移动路径未走过,移动
if(map[temp_x][temp_y]!='#' && visited_map[temp_x][temp_y]==0)
{
visited_map[temp_x][temp_y]=1; // 标记已走过
DFS(map,visited_map,temp_x,temp_y,step+1);
visited_map[temp_x][temp_y]=0; // 标记未走过
}
}
}
int main()
{
int T;
std::cin>>T;
while (T--)
{
int N,M;//N行,M列
std::cin>> N >> M;
std::vector<std::vector<char >> map(N,std::vector<char>(M)); // 地图初始化
std::vector<std::vector<int >> visited_map(N,std::vector<int>(M,0)); // 路径地图标记
min_step = 9999999; // 初始化最小步数
isFind = false; // 初始化未找到
// 记录地图
for(int i = 0; i<N ;i++)
{
for(int j = 0; j < M; j++)
{
std::cin>> map[i][j];
// 记录开始坐标
if(map[i][j]=='S')
{
start_position[0] = i;
start_position[1] = j;
}
// 记录结束坐标
if(map[i][j] == 'E')
{
end_position[0] = i;
end_position[1] = j;
}
}
}
// 起点标记走过
visited_map[start_position[0]][start_position[1]]==1;
DFS(map,visited_map,start_position[0],start_position[1],0);
if(isFind == true)
{
std::cout<<min_step<<"\n";
}
else
{
std::cout<<"-1\n";
}
}
}
题目 D: n皇后
题目描述
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与它处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
你的任务是求n个皇后在棋盘上不同的方法数。
输入
有多行(至多10组),每行一个正整数n,n<=12。
输出
对每个正整数n,输出n个皇后在棋盘上不同的方法数。
样例输入
4
6
样例输出
2
4
参考答案:
#include<iostream>
#include<vector>
int count ; // 方法数量
bool IsLeagal(std::vector<int >& queen,int row,int n)
{
for(int i = 0;i<row;i++)
{
// 当前皇后所在列与之前皇后所在列相等 或 在45度斜线上(当前皇后所在列与之前皇后所在列的差 等 当前皇后所在行与之前皇后所在行)
if(queen[i] == n || std::abs(row - i) == std::abs(n - queen[i]))//queen[n] == queen[i] || std::abs(queen[n]-queen[i]) == std::abs(n-i) )
{
return false;
}
}
// 当前皇后所在列与之前皇后所在列不相等 且 不在45度斜线上(当前皇后所在列与之前皇后所在列的差 不等 当前皇后所在行与之前皇后所在行)
return true;
}
// 第i行,共n行
void DFS(std::vector<int >& queen,int row,int n)
{
if( row == n) // 此时n行摆放完成
{
count ++; // 方案数+1
return ;
}
for(int i = 0; i< n ;i++) // 逐个判断每一列
{
if(IsLeagal(queen,row,i)) // 判断当前位置摆放是否合法
{
queen[row] = i; // 记录当前行摆在哪一列
DFS(queen,row+1,n); // 下一行开始
}
}
}
int main()
{
int n;
while(std::cin>>n)
{
count = 0;
std::vector<int > queen(n,0); // 下标代表所在行,对应的值记录所在列
DFS(queen,0,n); // 从第一行开始
std::cout<<count<<"\n";
}
}
// 排列树
#include <bits/stdc++.h>
using namespace std;
int n; // n皇后
int count_result; // 解的数量
bool IsLegal(vector<int>& queenPos, int row) {
// 判断当前位置是否可以放置皇后
for (int i = 1; i < row; ++i) {
// 遍历当前行之前的行
if ( abs(i - row) == abs(queenPos[i] - queenPos[row]) ) {
// 若斜线上有皇后,则当前位置不可放置
return false;
}
}
return true;
}
void SolutionOfNQueenProblem(vector<int>& queenPos, int row) {
if (row > n) {
// 若当前行超过最后一行,说明求得一解
++count_result;
return;
}
for (int i = row; i <= n; ++i) {
// 依次交换当前行与后面的每一行
swap(queenPos[i], queenPos[row]);
if ( IsLegal(queenPos, row) ) {
// 若当前行皇后的位置合法,进入下一行
SolutionOfNQueenProblem(queenPos, row + 1);
}
swap(queenPos[i], queenPos[row]);
}
}
int main(int argc, char const *argv[]) {
while (cin >> n) {
vector<int> queenPos(n + 1); // 皇后在棋盘中的位置,下标代表行数,值代表列数
count_result = 0; // 重置计数器
for (int i = 1; i <= n; ++i) {
queenPos[i] = i; // 假设第 i 行的皇后在第 i 列上
}
SolutionOfNQueenProblem(queenPos, 1);
cout << count_result << endl;
}
return 0;
}
题目 E: 最大装载问题
题目描述
有n个集装箱要装上一艘载重量c的轮船,其中第i个集装箱的重量为wi,i=1,2,...,n.要求确定一个合理的装载方案使装上船的集装箱重量之和最大。
输入
输入有若干组测试数据(不超过10组)。
每组测试数据有2行:其第1行上是集装箱个数n(n<=20)和船的载重量c,第2行上有n个整数w1、w2、…、wn,整数之间用一个空格分开,这n个整数依次表示这n个集装箱的重量(0<wi <1000,i=1,2,…,n,0<c<30000)。
输出
对输入的每组测试数据,输出装上船的集装箱重量之和的最大重量。
样例输入
3 50
10 40 40
3 50
20 40 40
样例输出
50
40
参考答案:
#include <iostream>
#include <vector>
int max_weight; // 最大重量
int n, capacity; // 物品数量,最大容量
// 货物,标记,当前重量,装载第几个
void DFS(std::vector<int> &items,int capacity, int weight, int num_th)
{
// 优先更新最大值,因为此时的weight是前num_th-1个物品的最大重量。
// 更新最大值
if(weight <= capacity)
{
max_weight = std::max(weight, max_weight);
}
if (num_th == n) // 最后一个结束
{
return;
}
DFS(items, capacity, weight, num_th + 1); // 不装,跳过,去尝试装下一个
DFS(items, capacity, weight+items[num_th], num_th + 1); // 装,从第i+1个开始继续深搜
}
int main()
{
while (std::cin >> n >> capacity)
{
std::vector<int> items(n, 0);
max_weight = 0;
for (int i = 0; i < n; i++)
{
std::cin >> items[i];
}
DFS(items,capacity, 0,0);
std::cout << max_weight << "\n";
}
}
题目 F: 跳马问题(2点)
题目描述
给定8*8方格棋盘。给定棋盘上两点,求一只马从一个位置到达另一位置的最短路径长。注意马是走“日”形的。
输入
输入有若干测试数据。
每组测试数据仅1行,每行上有2个方格pos1、pos2,之间用一个空格隔开,每格方格表示棋盘上的一个位置,该位置由表示列的1个字母(a-h)及表示行的一个数字(1-8)构成,如“d7”表示第4列第7行。
输出
对输入中每行上的2个方格pos1、pos2,输出马从位置pos1跳到pos2所需的最短路径长。如“a1==>a2: 3 moves”表示从位置a1跳到a2所需的最少步数是3。
注意:按输出样例所示格式输出,如“a1==>a2: 3 moves”中冒号后有一个空格,再输出所需的最少步数。
样例输入
a1 a2
a1 a3
a1 h8
样例输出
a1==>a2: 3 moves
a1==>a3: 2 moves
a1==>h8: 6 moves
参考答案:
#include <iostream>
#include <vector>
#include <queue>
int min_step;
struct point_info
{
int x,y;
int step;
};
void BFS(std::vector<std::vector<int> > checkerBoard,int x,int y,int end_x,int end_y)
{
int dx[8] ={1,2,2,1,-1,-2,-2,-1};
int dy[8] ={2,1,-1,-2,-2,-1,1,2};
std::queue<point_info> bfs_queue;
point_info start_pos;
start_pos.step=0;
start_pos.x = x;
start_pos.y = y;
bfs_queue.push(start_pos);
while(!bfs_queue.empty())
{
if( bfs_queue.front().x == end_x && bfs_queue.front().y == end_y)
{
min_step = bfs_queue.front().step;
return;
}
for(int i = 0; i<8;i++)
{
int temp_x = bfs_queue.front().x + dx[i];
int temp_y = bfs_queue.front().y + dy[i];
if(temp_x < 1 || temp_x >8 || temp_y < 1 || temp_y > 8 )
continue;
if(checkerBoard[temp_x][temp_y]==0)
{
point_info temp_pos;
temp_pos.x = temp_x;
temp_pos.y = temp_y;
temp_pos.step = bfs_queue.front().step+1;
bfs_queue.push(temp_pos);
checkerBoard[temp_x][temp_y] = 1;
}
}
bfs_queue.pop();
}
return ;
}
int main()
{
std::vector<std::vector<int> > checkerBoard(9, std::vector<int>(9, 0));
for (int i = 0; i < 9; i++)
{
checkerBoard[0][i] = 1;
checkerBoard[i][0] = 1;
}
std::string start_pos;
std::string end_pos;
while (std::cin>>start_pos>>end_pos)
{
int start_x,start_y,end_x,end_y;
min_step = 999999;
start_x = start_pos[0] - 'a' + 1;
start_y = start_pos[1] - '1' + 1;
end_x = end_pos[0] - 'a' + 1;
end_y = end_pos[1] - '1' + 1;
BFS(checkerBoard,start_x,start_y,end_x,end_y);
std::cout<<start_pos<<"==>"<<end_pos<<": "<<min_step<<" moves\n";
}
}
题目 G: 布线问题
题目描述
问题描述
印刷电路板的布线区域是一个m×n的方格阵列,该电路板可能有一些布过线的,已布线的方格做封锁标记,
如图。现有2个方格A、B,需确定方格A的中心到方格B的中心的最短布线方案。
布线要求,沿直线或直角进行,但不走对角线,线路不允许穿过被封锁的方格。
输入
输入有若干测试数据。每组测试数据的第一行上有2个整数m、n,分别表示电路板的高和宽,
接着是m行每行有n个数,表示这个电路板的描述,这n个数是0、1构成,其中1表示是被封锁的方格。
最后一行上有4个整数正整数x1,y1,x2,y2,其中(x1,y1)表示A的位置,(x2,y2)表示B的位置,(2<=m,n<=20,1<=x1,x2<=m,1<=y1,y2<=n),
整数之间用一个空格隔开。
输出
对每组测试数据,输出从位置A到B所布的最短线路的长度。
样例输入
5 5
0 0 1 1 0
0 0 1 0 0
0 0 0 1 0
0 0 0 1 0
0 0 0 0 0
3 2 2 4
8 8
0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0
0 0 0 1 0 1 1 0
0 0 0 1 0 0 0 0
0 0 1 1 0 0 1 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
2 3 6 7
样例输出
9
12
参考答案:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int startx, starty, endx, endy;//定义起点坐标和终点坐标
int mapp_x, mapp_y;//地图行列
int minn;//先设最短路径为不可达到的大数字
//int mapp[1000][1000];//也可以开较大数组,数组不要开太大,不然会内存超限的
//路径点结构体,存放坐标和到达当前点时的步数
struct position
{
int x, y;
int step;
};
void BreadthFS(int x, int y, int step, vector<vector<int>> mapp)
{
//右、下、左、上
int nextx[4] = { 1,0,-1,0 };
int nexty[4] = { 0,-1,0,1 };
//长度为3的数组存放坐标x,y和步数step
//1、x 2、y 3、step
//queue<int[3]> route;
queue<position> route;//声明路线队列
position startPos;//声明起点结构体
startPos.x = x;//传入起点x坐标
startPos.y = y;//传入起点y坐标
startPos.step = step;//传入到达起点时的步数
route.push(startPos);//将起点压入队列
while (!route.empty())
{
int x = route.front().x;//得到队首元素的x坐标
int y = route.front().y;//得到队首元素的y坐标
if (x == endx-1 && y == endy-1)//到达终点
{
//更新最小值
if (route.front().step < minn)//记得换成队首元素的步数
minn = route.front().step;//得到最短路径
return;
}
for (int k = 0; k < 4; k++)//四个方向的循环
{
int tx = route.front().x + nextx[k];//x方向的拓展
int ty = route.front().y + nexty[k];//y方向的拓展
if (tx < 0 || tx >= mapp_x || ty < 0 || ty >= mapp_y)//如果越界就跳过
continue;
if (mapp[tx][ty] == 0)//如果是可行点则将此点入队
{
position temp;
temp.x = tx;
temp.y = ty;
temp.step = route.front().step + 1;//入队的点是队首元素的步数+1
route.push(temp);//此点入队
mapp[tx][ty] = 2;//设置为已经走过
}
}
route.pop();//队首元素出队
}
return;
}
int main()
{
while (cin >> mapp_x >> mapp_y)
{
vector<vector<int>> mapp(mapp_x, vector<int>(mapp_y, 0));//定义地图
for(int i = 0;i<mapp_x;i++)
{
for(int j = 0; j<mapp_y;j++)
{
cin>>mapp[i][j];
}
}
cin >> startx >> starty >> endx >> endy;//输入起点坐标和终点坐标
minn = 99999999;//先设最短路径为不可达到的大数字
mapp[startx-1][starty-1] = 2;//设置起点已经走过
//广搜解决问题
BreadthFS(startx-1, starty-1, 0, mapp);
cout << minn<< endl;
}
return 0;
}