试题 算法提高 智能体系列赛 C

试题 算法提高 智能体系列赛

资源限制
时间限制: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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值