Robocom-2021初赛-打怪升级

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

你的任务有两件:

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

输入格式:

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

B1 B2 怪兽能量 武器价值

其中 B1B2 是怪兽把守的道路两端的堡垒编号。题目保证每对堡垒之间只有一只怪兽把守,并且 怪兽能量武器价值 都是不超过 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

 


一、参考其他博主的答案(原文链接:https://blog.youkuaiyun.com/qq_33957603/article/details/124525420

题意:给出n个点m条边的无向图,每条边有一个代价和一个价值,对于每个点求最大代价的点,记最小的为起点。然后从起点出发到其他所有点的最小代价路径,代价相同时找最大价值,打印路径。
思路:
floyed跑多源最短路,令最长路最短,即为起点RT。
Dijkstra跑单源最短路(w1最小,w2最大),打印路径即可。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
const int inf = 1e9+10;
const int maxn = 1010;

int e[maxn][maxn];
struct edge{ int to, w1, w2; };
vector<edge>G[maxn];
struct node{
    int u, w1, w2; 
    bool operator < (const node &b)const{ return w1!=b.w1 ? w1>b.w1 : w2<b.w2; }
};

int dist[maxn], dist2[maxn], vis[maxn], pre[maxn];
void print(int x){
    if(pre[x]==-1)return ;
    print(pre[x]);
    cout<<"->"<<x;
}

int main(){
    memset(e,0x3f,sizeof(e)); //WA2
    int n, m;  cin>>n>>m;
    for(int i = 1; i <= m; i++){
        int u, v, w1, w2;  cin>>u>>v>>w1>>w2;
        e[u][v] = e[v][u] = w1;
        G[u].push_back({v,w1,w2});
        G[v].push_back({u,w1,w2});
    }
    //1, floyed跑多源,令最长路最短
    for(int k = 1; k <= n; k++){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                e[i][j] = min(e[i][j], e[i][k]+e[k][j]);
            }
        }
    }
    int rt = -1, mx = inf;
    for(int i = 1; i <= n; i++){
        int tmp = 0;
        for(int j = 1; j <= n; j++)
            tmp = max(tmp, e[i][j]);
        if(tmp < mx){
            mx = tmp;  rt = i;
        }
    }
    //2, Dijkstra跑单源,打印路径
    for(int i = 1; i <= n; i++)dist[i] = inf, pre[i] = -1;
    priority_queue<node>q;
    dist[rt] = 0, dist2[rt] = 0;
    q.push({rt,dist[rt],dist2[rt]});
    while(q.size()){
        int u = q.top().u;  q.pop();
        if(vis[u])continue;
        vis[u] = 1;
        for(edge nt : G[u]){
            int v = nt.to;
            if(dist[v] > dist[u]+nt.w1){
                dist[v] = dist[u]+nt.w1;
                dist2[v] = dist2[u]+nt.w2;
                pre[v] = u;
                q.push({v,dist[v], dist2[v]});
            }else if(dist[v]==dist[u]+nt.w1 && dist2[nt.to]<dist2[u]+nt.w2){
                dist2[v] = dist2[u]+nt.w2;
                pre[v] = u;
                q.push({v,dist[v], dist2[v]});
            }
        }
    }
    //3, T次打印
    cout<<rt<<"\n";
    int T;  cin>>T;
    while(T--){
        int x;  cin>>x;
        cout<<rt;
        print(x);
        cout<<"\n";
        cout<<dist[x]<<" "<<dist2[x]<<"\n";
    }
    return 0;
}



————————————————
版权声明:本文为优快云博主「小哈里」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/qq_33957603/article/details/124525420

二、总结

1.根据题意,在计算出发点时,是依据整体,而不是玩家的目标堡垒

2.Dijkstra时,要记录前一个点是什么

3.学习存储邻接点

G[u].push_back({v,w1,w2});

G[v].push_back({u,w1,w2});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blossom๑.๑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值