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

考点:Floyd,dijkstra变式(记录路径,多优先级)

7-3 打怪升级 (25分)

很多游戏都有打怪升级的环节,玩家需要打败一系列怪兽去赢取成就和徽章。这里我们考虑一种简单的打怪升级游戏,游戏规则是,给定有 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

编译器

NO_COMPILER

代码

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

int n, m, a, b, c, d, q, p;
int f[1005][1005];

const int N = 2000000;
int ne[N], w[N], ww[N], e[N], h[N], idx, dist[1005];
bool st[1005];

struct node{
	int distance, power, name;
};

struct cmp{
	bool operator() (node x, node y){
		if(x.distance != y.distance) return x.distance > y.distance;
		else{
			if(x.power != y.power) return x.power < y.power;
			else return x.name < y.name;
		} 
	}
}; 

int pre[1005];//难点1
int pw[1005];//难点2 

void add(int a, int b, int c, int d){
	e[idx] = b, w[idx] = c, ww[idx] = d, ne[idx] = h[a], h[a] = idx++;
}

void dijk(int s){
	priority_queue<node, vector<node>, cmp> heap;
	heap.push({0, 0, s});
	dist[s] = 0;
	while(heap.size()){
		node head = heap.top();
		heap.pop();
		int ver = head.name, distance = head.distance, power = head.power;
		if(st[ver]) continue;
		st[ver] = 1;
		
		for(int i = h[ver]; i!=-1; i = ne[i]){
			int j = e[i];
			if(distance + w[i] < dist[j]){
				pre[j] = ver;
				dist[j] = distance + w[i];
				pw[j] = power + ww[i];
				heap.push({dist[j], pw[j], j});
			}
			else if(distance + w[i] == dist[j]){
				if(power + ww[i] > pw[j]){
					pre[j] = ver;
					dist[j] = distance + w[i];
					pw[j] = power + ww[i];
					heap.push({dist[j], pw[j], j});
				}
			}
		}
	}
//	cout<<"debug";
}

int main(){
	memset(h, -1, sizeof h);
	memset(dist, 127, sizeof dist);
	
	cin>>n>>m;
	memset(f, 63, sizeof f);
	for(int i = 1; i<=m; ++i){
		cin>>a>>b>>c>>d;
		f[a][b] = c;
		f[b][a] = c;
		add(a,b,c,d);
		add(b,a,c,d);
	}

	for(int k = 1; k<=n; ++k)
		for(int i = 1; i<=n; ++i)
			for(int j = 1; j<=n; ++j)
				f[i][j] = min(f[i][j], f[i][k] + f[k][j]);

	int ans1 = 0;
	int ans1max = 100000000;
	for(int i = 1; i<=n; ++i){
		int curmax = 0;
		for(int j = 1; j<=n; ++j){
			curmax = max(curmax, f[i][j]);
		}
		if(curmax<ans1max){
			ans1 = i;
			ans1max = curmax;
		}
	}
	cout<<ans1<<endl;

	dijk(ans1);
	cin>>q;
	for(int i = 1; i<=q; ++i){
		cin>>p;
		vector<int> ans2;
		
		int cur = p;
		while(cur!=ans1){
			ans2.push_back(cur);
			cur = pre[cur];
		}
		ans2.push_back(ans1);
		
		for(int i = ans2.size()-1; i>=0; --i){
			cout<<ans2[i];
			if(i!=0) cout<<"->";
		}
		cout<<"\n";		
		
		cout<<dist[p]<<" "<<pw[p]<<endl;
	}

    return 0;
}

编译器输出

 
测试点结果测试点得分耗时内存
0答案正确1312.00 ms12348 KB
1答案正确512.00 ms12228 KB
2答案正确112.00 ms12352 KB
3答案正确2813.00 ms12392 KB
4答案正确41154.00 ms30820 KB

评测结果 答案正确(25 分)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值