2021 RoboCom 世界机器人开发者大赛-本科组(初赛)7-3 打怪升级 (25 分)

这篇博客介绍了一个简单的打怪升级游戏的解决方案,玩家需要在给定的堡垒网络中找到最佳空降点,以最小能量攻下最难关卡。通过Floyd算法确定空降位置,然后使用Dijkstra算法找出从空降点到目标堡垒的最短路径和最高收益。博主提供了详细的算法实现和输出示例,帮助玩家制定最优策略。
摘要由CSDN通过智能技术生成

dgsj.JPG

很多游戏都有打怪升级的环节,玩家需要打败一系列怪兽去赢取成就和徽章。这里我们考虑一种简单的打怪升级游戏,游戏规则是,给定有 N 个堡垒的地图,堡垒之间有道路相连,每条道路上有一只怪兽把守。怪兽本身有能量,手里的武器有价值。打败怪兽需要的能量等于怪兽本身的能量,而怪兽一旦被打败,武器就归玩家所有 —— 当然缴获的武器价值越高,玩家就越开心。

你的任务有两件:

    1. 帮助玩家确定一个最合算的空降位置,即空降到地图中的某个堡垒,使得玩家从这个空降点出发,到攻下最难攻克(即耗费能量最多)的那个堡垒所需要的能量最小;
    1. 从这个空降点出发,帮助玩家找到攻克任意一个其想要攻克的堡垒的最省能量的路径。如果这种路径不唯一,则选择沿途缴获武器总价值最高的解,题目保证这种解是唯一的。

输入格式:

输入第一行给出两个正整数 N (≤1000) 和 M,其中 N 是堡垒总数,M 是怪兽总数。为简单起见,我们将堡垒从 1 到 N 编号。随后 M 行,第 i 行给出了第 i 只怪兽的信息,格式如下:

B1 B2 怪兽能量 武器价值

其中 B1 和 B2 是怪兽把守的道路两端的堡垒编号。题目保证每对堡垒之间只有一只怪兽把守,并且 怪兽能量 和 武器价值 都是不超过 100 的正整数。

再后面是一个正整数 K(≤N)和玩家想要攻克的 K 个目标堡垒的编号。

输出格式:

首先在一行中输出玩家空降的堡垒编号 B0。如果有多种可能,则输出编号最小的那个。

随后依次为玩家想要攻克的每个堡垒 B 推荐最省能量的攻克路径,并列出需要耗费的能量值和沿途缴获武器的总价值。注意如果最省力的路径不唯一,则选择沿途缴获武器总价值最高的解。格式为:

B0->途经堡垒1->...->B
总耗费能量 武器总价值

输入样例:

6 12
1 2 10 5
2 3 16 20
3 1 4 2
2 4 20 22
4 5 2 2
5 3 12 6
4 6 8 5
6 5 10 5
6 1 20 25
1 5 8 5
2 5 2 1
2 6 8 5
4
2 3 6 5

输出样例:

5
5->2
2 1
5->1->3
12 7
5->4->6
10 7
5
0 0

思路:枚举每个点s,以s为起点跑最短路,暴力求出最合理的空降位置(Floyd)。以空降位置再跑一遍最短路,维护出双关键字最短路径和路径信息,最后按题意输出路径即可。这一步的具体做法参考城市救援

时间复杂度O(n^3)。

 

 

#include<iostream> 
#include<cstring>
#include<unordered_map>
#include<vector>
#include<stack>
using namespace std;
const int INF = 0x3f3f3f3f, N = 1010, M = N*N;
struct Edge{
	int w=INF,x=0;//w怪兽价值 x武器价值 
}g[N][N];
int gg[N][N]; 
int d[N],wdis[N],xdis[N];//wdis为到空降位置的最短路径,xdis为武器价值 
int path[N];//记录路径信息 
bool book[N];
int n,m;
int Floyd(){//计算空降位置 
	int num,minn = INF;
	for(int k = 1; k <= n; k++){
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(gg[i][j] > gg[i][k] + gg[k][j]){
					gg[i][j] = gg[i][k] + gg[k][j];
				}
			}
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(gg[i][j]!=INF) d[i] = max(d[i],gg[i][j]);
		}
		if(minn > d[i]){
			minn = d[i];
			num = i;
		}
	}
	return num; 
} 
void Djkstra(int idx){//获得最短路径信息 
    //由于每次都只选离源点最近的点标记,且已标记的点最短路径信息不可改变
    //所以可以记录所有点到源点的路径信息。
	wdis[idx] = 0;
	xdis[idx] = 0;
	for(int j = 1; j <= n; j++){
		int wminn = INF;
		int xmax = 0;
		int p = -1;
		for(int i = 1; i <= n; i++){
			if(!book[i] && (wminn > wdis[i] || (wminn == wdis[i] && xmax < xdis[i]))){
				wminn = wdis[i];
				xmax = xdis[i];
				p = i;
			}
		}
		book[p] = true;
		for(int i = 1; i <= n; i++){
			if(!book[i] && g[p][i].w != INF){
				if(wdis[i] > wdis[p] + g[p][i].w){
					wdis[i] = wdis[p] + g[p][i].w;
					xdis[i] = xdis[p] + g[p][i].x;
					path[i] = p;
				} else if((wdis[i] == wdis[p] + g[p][i].w) && (xdis[i] < xdis[p] + g[p][i].x)) {
					xdis[i] = xdis[p] + g[p][i].x;
					path[i] = p;
				}
			}
		}
	}
	
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	memset(wdis,0x3f,sizeof(wdis));
    memset(gg,0x3f,sizeof(gg));
	for(int i = 0; i < m; i++){
		int u,v,w,x;
		cin>>u>>v>>w>>x;
		g[u][v].w = g[v][u].w = w;//Djkstra需要
		g[u][v].x = g[v][u].x = x;
		gg[u][v] = gg[v][u] = w;//Floyd需要
	}
	int num = Floyd();
	Djkstra(num);//获得所有点到num点的最短路径信息path
	cout<<num<<'\n';
	int k;
	cin>>k;
	for(int i = 0; i < k; i++){
		if(i) cout<<'\n';
		int x;
		cin>>x;
		int ww = wdis[x],xx = xdis[x];
        //对最短路径信息path进行处理
		stack<int> pt;
		while(x!=num){
			pt.push(x);
			x = path[x];
		}
		cout<<num; 
		while(pt.size()){
			cout<<"->"<<pt.top();
			pt.pop();
		}
		cout<<'\n'<<ww<<' '<<xx;
	}
	return 0;
}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值