7-3 打怪升级

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

先分析一下题目要求我们干啥

首先找出一个到该节点路径所需能量的最小值

做法:我们可以遍历每一个点,找出每个点到以该点作为起点的最小值(dijkstra)

这些最小值中的最大值即为以该顶点为起点,最难攻破的点

枚举每个起点,每个起点最难攻破的最小值即为我们要求的点

其次,我们要求出以该起点到所想到达点的路径和距离

可以用pre记录即可

代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N=1010;

int S[N][N],D[N][N];
int max_d[N],min_s[N],max_s[N];
int n,m;
int a,b,s,d;
bool vis[N];
int pre[N];

int dijkstra(int f)
{
    memset(vis,0,sizeof vis);
    memset(min_s,0x3f,sizeof min_s);
    memset(max_d,0,sizeof max_d);

    min_s[f]=0;
    while(true)
    {
        int t=-1;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&(min_s[t]>min_s[i]||t==-1)) t=i;
            
        }
        if(t==-1) break;
            vis[t]=true;
        for(int i=1;i<=n;i++)
        {
            if(min_s[i]>min_s[t]+S[t][i])
            {
                pre[i]=t;
                min_s[i]=min_s[t]+S[t][i];
                max_d[i]=max_d[t]+D[t][i];
            }
            else if(min_s[i]==min_s[t]+S[t][i])
            {
                if(max_d[i]<max_d[t]+D[t][i])
                {
                    pre[i]=t;
                    max_d[i]=max_d[t]+D[t][i];
                }
            }
        }
    }
    int mf=0;
    for(int i=1;i<=n;i++)
        if(mf<min_s[i]) mf=min_s[i];
    return mf;
}

void dfs(int x,int id)
{
    if(x==id) return;
    dfs(pre[x],id);
    printf("->%d",x);
}

int main()
{
    memset(S,0x3f,sizeof S);
    scanf("%d %d",&n,&m);
    while(m--)
    {
        scanf("%d %d %d %d",&a,&b,&s,&d);
        S[a][b]=S[b][a]=s;
        D[a][b]=D[b][a]=d;
    }
    for(int i=1;i<=n;i++)
    max_s[i]=dijkstra(i);

    int id=1;
    for(int i=1;i<=n;i++)
        if(max_s[id]>max_s[i])
        {
            max_s[id]=max_s[i];
            id=i;
        }
    printf("%d\n",id);
    dijkstra(id);
    int k,x;
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d",&x);
        printf("%d",id);
        dfs(x,id);
        printf("\n");
        printf("%d %d\n",min_s[x],max_d[x]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值