试题 算法提高 智能体系列赛
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
zsyzgu是一个弱菜,尽管如此他还是参加了智能体系列赛。智能体系列赛的问题经简化后是这样的,有一只猴子和一些矿点,知道他们在平面上的坐标,这只猴子要经过这些矿点至少一次。假设这只猴子从点A走到点B所要花费的步数是这两个点的曼哈顿距离(即|A.x-B.x|+|A.y-B.y|),问这只猴子经过这些矿点至少一次所需的最少步数。
系列赛中的许多选手都用了贪心的策略,即每次都到最近的没经过的矿点去。但zsyzgu的思路是搜索,这也是他能够摆脱垫底命运获得纪念版T-shirt的原因。
输入格式
第一行两个数表示猴子的坐标;
第二行一个数n表示矿点数;
接下来n行每行两个数表示每个矿点的坐标。
输出格式
一行一个数表示最少步数。
样例输入
0 0
4
0 1
0 2
0 3
0 -2
样例输出
7
数据规模和约定
对于100%的数据:1<=n<=10,横纵坐标都是整数,其的绝对值<=10000。
解题:
由题目可知,需要采用搜索的思路进行答题
思路如下:
- 首先我们需要确定猴子从初始点开始的第一步到达的矿点是哪个
- 以第一步到达的矿点为搜索起点,将所有的矿点都走一遍,这里用一个额外数组 isvisit 去判断是否已经走过该矿点
- 每一轮搜索结束后判断这种走法所需要的步数是否更少,并进行回溯,即将该矿点重新标记为未访问,直至所有的方案全部搜索结束
代码如下:
#include <stdio.h>
#include <stdlib.h>
//#include <math.h>
//#include <string.h>
//#include <stdbool.h>
int n; // 矿点数量
int min_step; // 最小步数
int* isvisit; // 记录矿点是否已访问
void dfs(int** Orenode, int loc, int cur, int step){
if(cur == n){ // 当所有矿点都走过了
min_step = step<min_step?step:min_step; // 查看此时的步数是否为最小值
return;
}
isvisit[loc] = 1; // 标记该矿点为已走过
int i = 0;
for(i = 0; i < n; i++){
if(!isvisit[i]){
// 计算曼哈顿距离并进行搜索
int temp = abs(Orenode[i][0]-Orenode[loc][0]) + abs(Orenode[i][1]-Orenode[loc][1]);
dfs(Orenode, i, cur+1, step+temp);
}
}
isvisit[loc] = 0; // 回溯,重新标记为未走过
}
int main(){
min_step = 1e6; // 初始化最小步数
int begin_x, begin_y;
scanf("%d %d", &begin_x, &begin_y);
scanf("%d", &n);
int** Orenode = (int**)malloc(sizeof(int*)*n); // 矿点坐标
isvisit = (int*)calloc(n, sizeof(int));
int i = 0;
// 存入所有矿点坐标
for(i = 0; i < n; i++){
Orenode[i] = (int*)malloc(sizeof(int)*2);
scanf("%d %d", &Orenode[i][0], &Orenode[i][1]);
}
int loc = 0;
for(loc = 0; loc < n; loc++){
// 以标号为 loc的矿点为第一步,即搜索起点
int begin_step = abs(begin_x-Orenode[loc][0]) + abs(begin_y-Orenode[loc][1]);
dfs(Orenode, loc, 1, begin_step);
}
printf("%d", min_step);
return 0;
}