赞
踩
注意, 本题解默认观看者理解dijkstra、floyd算法, 熟悉图的存储方式
很多游戏都有打怪升级的环节,玩家需要打败一系列怪兽去赢取成就和徽章。这里我们考虑一种简单的打怪升级游戏,游戏规则是,给定有 N 个堡垒的地图,堡垒之间有道路相连,每条道路上有一只怪兽把守。怪兽本身有能量,手里的武器有价值。打败怪兽需要的能量等于怪兽本身的能量,而怪兽一旦被打败,武器就归玩家所有 —— 当然缴获的武器价值越高,玩家就越开心。
你的任务有两件:
帮助玩家确定一个最合算的空降位置,即空降到地图中的某个堡垒,使得玩家从这个空降点出发,到攻下最难攻克(即耗费能量最多)的那个堡垒所需要的能量最小;
从这个空降点出发,帮助玩家找到攻克任意一个其想要攻克的堡垒的最省能量的路径。如果这种路径不唯一,则选择沿途缴获武器总价值最高的解,题目保证这种解是唯一的。
输入格式
输入第一行给出两个正整数 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
给定有 N 个堡垒的地图,堡垒之间有道路相连
解释:给定n个顶点的无向图, 且保证为连通图
每条道路上有一只怪兽把守。怪兽本身有能量,手里的武器有价值。打败怪兽需要的能量等于怪兽本身的能量
解释: 图中无重边, 每条边有两个权值, 分别为能量(距离) 和 价值(次权)
要求一
帮助玩家确定一个最合算的空降位置,即空降到地图中的某个堡垒,使得玩家从这个空降点出发,到攻下最难攻克(即耗费能量最多)的那个堡垒所需要的能量最小;
解释: 要分别求出图中每个顶点为起点的最短路径信息, 取最短路径信息中最大值最小的顶点为空降位置.要求一中只涉及路径(能量), 并没有涉及另一个权
要求二
从这个空降点出发,帮助玩家找到攻克任意一个其想要攻克的堡垒的最省能量的路径。如果这种路径不唯一,则选择沿途缴获武器总价值最高的解,题目保证这种解是唯一的。
解释: 以空降点为其它获取它的双权最短路径, 其中能量为主权, 只有能量相等时才会比较武器价值.
并且要记录路径, 后续输出.
对于要求一, 是一个多源单权最短路径问题, 使用floyd算法尤为方便.
用一个邻接矩阵存储图的能量信息, 对其使用floyd, 再在结果中找到空降点.
int g[N][N]; void floyd() { for(int i=1; i<=n; i++) for(int x=1; x<=n; x++) for(int y=x+1; y<=n; y++) g[x][y] = g[y][x] = min(g[x][y], g[x][i]+g[i][y]); } //找出空降点 int Find() { int res, minE = INF; for(int i=1; i<=n; i++) { int maxE = 0; for(int j=1; j<=n; j++) if(g[i][j] > maxE && i!=j) maxE = g[i][j]; if(maxE < minE) { res = i; minE = maxE; } } return res; }
对于要求二, 是一个单源双权最短路径问题, 使用dijkstra算法较为方便. 因为是dijkstra算法并且有双权, 所以这里用前向星来保存图的信息
//we为能量权, wv为价值权
int h[N], we[N], wv[N], e[N], ne[N], idx;
在dijkstra算法过程中我们不仅要维护最短距离/能量(dist)、状态数组vis、路径数组path, 还要维护最大价值value, 以确保最短距离的正确性
int dist[N];
int value[N];
bool vis[N];
int path[N];
为了方便, 使用了朴素版dijkstra
void dijkstra(int bg) { memset(dist, 0x3f, sizeof dist); dist[bg] = 0; for(int i=1; i<=n; i++) { int t = -1; for(int j=1; j<=n; j++) if(!vis[j] && (t==-1 || dist[j] < dist[t])) t = j; for(int j=h[t]; j!=-1; j=ne[j]) { int dest = e[j]; //有两种情况要进行更新:路径较之前的小 或路径相同但价值较之前的大 if((dist[dest] > dist[t] + we[j]) || (dist[dest] == dist[t] + we[j] && value[dest] < value[t] + wv[j])) { dist[dest] = dist[t] + we[j]; value[dest] = value[t] + wv[j]; path[dest] = t; } } vis[t] = true; } }
最后递归打印路径
void PrintPath(int bg, int tar)
{
if(bg == tar)
{
cout << bg;
return;
}
else PrintPath(bg, path[tar]);
cout << "->" << tar;
}
// // Created by trudbot on 2022/7/8. // #include <bits/stdc++.h> #define ll long long #define pii pair<int, int> #define INF 0x3f3f3f3f using namespace std; #define N 1010 int n, m; int g[N][N]; int h[N], we[N], wv[N], e[N], ne[N], idx; int dist[N]; int value[N]; bool vis[N]; int path[N]; void add(int x, int y, int z, int v) { wv[idx] = v, we[idx] = z, e[idx] = y, ne[idx] = h[x], h[x] = idx++; } void floyd() { for(int i=1; i<=n; i++) for(int x=1; x<=n; x++) for(int y=x+1; y<=n; y++) g[x][y] = g[y][x] = min(g[x][y], g[x][i]+g[i][y]); } int Find() { int res, minE = INF; for(int i=1; i<=n; i++) { int maxE = 0; for(int j=1; j<=n; j++) if(g[i][j] > maxE && i!=j) maxE = g[i][j]; if(maxE < minE) { res = i; minE = maxE; } } return res; } void dijkstra(int bg) { memset(dist, 0x3f, sizeof dist); dist[bg] = 0; for(int i=1; i<=n; i++) { int t = -1; for(int j=1; j<=n; j++) if(!vis[j] && (t==-1 || dist[j] < dist[t])) t = j; for(int j=h[t]; j!=-1; j=ne[j]) { int dest = e[j]; if((dist[dest] > dist[t] + we[j]) || (dist[dest] == dist[t] + we[j] && value[dest] < value[t] + wv[j])) { dist[dest] = dist[t] + we[j]; value[dest] = value[t] + wv[j]; path[dest] = t; } } vis[t] = true; } } void PrintPath(int bg, int tar) { if(bg == tar) { cout << bg; return; } else PrintPath(bg, path[tar]); cout << "->" << tar; } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); memset(h, -1, sizeof h); memset(g, 0x3f, sizeof g); cin >> n >> m; int x, y, z, v; while (m--) { cin >> x >> y >> z >> v; g[x][y] = g[y][x] = z; add(x, y, z, v); add(y, x, z, v); } floyd(); int bg = Find(); cout << bg << endl; dijkstra(bg); int k; cin >> k; int tar; while(k--) { cin >> tar; PrintPath(bg, tar); cout << endl; cout << dist[tar] << " " << value[tar] << endl; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。