Gym - 101873C 两种因素影响下的dijkstra

转自:https://www.cnblogs.com/dilthey/p/9928485.html 对代码写了一些注释
题目链接:https://vjudge.net/problem/Gym-101873C
题意:这是七月的又一个阳光灿烂的日子,你决定和你的小女儿一起度过快乐的一天。因为她真的很喜欢隔壁镇上的仙女公园,所以你决定到那儿去玩一天。
你妻子同意开车送你去公园接你。她非常准时,所以她确切地告诉你她什么时候会到公园的前门来接你,而你必须恰好在那个时间到那里。因为你显然也不想在外面等,这样会让你的小女儿伤心——她本可以在公园里多待些时间。
现在你必须考虑游玩计划。你知道你什么时候到达,什么时候离开。公园由若干游玩设施组成,两两之间由人行道相连。进入公园是免费的,但你每次使用在公园里的某项设施,都必须付一次相应费用。你已经知道玩每一项游玩设施各自需要多长时间、花多少钱。
当你穿过公园时,你显然不能在沿着公园走的时候跳过游乐设施(即使乔伊已经用了),否则乔伊会很伤心。因为乔非常喜欢公园,她很乐意玩同一个项目不止一次。在两个游乐项目之间行走需要一定的时间。
因为你是一个有计划的家长,所以当你在公园的时候,你要尽量少花钱。你能计算至少要花多少钱吗?

输入:一行,一个整数 x(1≤x≤1e3) 代表你们在公园玩的确切时间。
一行,三个整数 n,m,t(1≤n,m,t≤1e3),代表有 n 个娱乐设施, 之间有 m 条人行道连接,走人行道需要花费 t 分钟。
m 行,每行 a,b 代表设施 a,b 之间有一条小路。
n 行,每行 t,p 代表该项游乐设施花费 t 分钟,p 元。
你从设施 1 出发,最后必须回到设施 1。
思路:在dijkstra上添加一个维度。因为是要求花钱最少,所以按花费钱的数量跑最短路,dist[v][k] 表示在 k 时刻走到点 v 最少花费 dist[v][t] 元。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int x,n,m,w;
int t[maxn],p[maxn];//每个设施花费时间 花费金钱
struct edge
{
    int u,v;
    edge()
    {

    }
    edge(int a,int b)
    {
        u=a;
        v=b;
    }
};
vector <edge> e;
vector <int> g[maxn];
void addedge(int u,int v)
{
    e.push_back(edge(u,v));
    g[u].push_back(e.size()-1);
}
struct node
{
    int v,k,d;//当前所在设施编号 已经花费的时间 花费的钱
    node()
    {

    }
    node(int a,int b,int c)
    {
        v=a;
        k=b;
        d=c;
    }
    bool operator <(const node &s)const
    {
        return d>s.d;
    }
};
int dist[maxn][maxn];
const int inf=0x3f3f3f;
bool vis[maxn][maxn];//访问标记
void dijkstra()
{
    memset(dist,inf,sizeof(dist));
    memset(vis,0,sizeof(vis));
    priority_queue<node> q;
    if(t[1]<=x)
        dist[1][t[1]]=p[1];
    else//第一个设施时间超过限定时间
        return ;
    q.push(node(1,t[1],p[1]));
    while(!q.empty())
    {
        int u=q.top().v,k=q.top().k;
        q.pop();
        if(vis[u][k])//已经访问过
            continue;
        vis[u][k]=true;
        if(k+t[u]<=x&&dist[u][k+t[u]]>dist[u][k]+p[u])//这个设施是否可以继续游玩一次
        {                                             //因为在添加进这个点之前这个设施已经被游玩过了
            dist[u][k+t[u]]=dist[u][k]+p[u];
            q.push(node(u,k+t[u],dist[u][k+t[u]]));
        }
        for(int i=0;i<g[u].size();i++)
        {
            edge &r=e[g[u][i]];
            int v=r.v;
            if(k+w+t[v]>x)//已经耗费的时间+走到此设施的时间+游玩此设施的时间超过限定时间
                continue;
            if(!vis[v][k+w+t[v]]&&dist[v][k+w+t[v]]>dist[u][k]+p[v])//这个设施没有被游玩过并且可以进行松弛操作
            {
                dist[v][k+w+t[v]]=dist[u][k]+p[v];
                q.push(node(v,k+w+t[v],dist[v][k+w+t[v]]));
            }
        }
    }
}
int main()
{int u,v;
    cin>>x>>n>>m>>w;//总共玩的时间 n个设施 m条人行道 人行道花费的时间
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        addedge(u,v);
        addedge(v,u);
    }
    for(int i=1;i<=n;i++)
    {
        cin>>t[i]>>p[i];
    }
    dijkstra();
    if(vis[1][x])
        cout<<dist[1][x]<<endl;
    else
        cout<<"It is a trap.\n";
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值