Vijos P1901 学姐的钱包

11 篇文章 0 订阅

描述
学姐每次出门逛街都要带恰好M元钱, 不过她今天却忘记带钱包了.
可怜的doc只好自己凑钱给学姐, 但是他口袋里只有一元钱.
好在doc的N位朋友们都特别有钱, 他们答应与doc作一些交换.
其中第i位朋友说:
如果doc有不少于Ri元钱,
doc可以把手上所有的钱都给这位朋友,
并从这位朋友手中换回Vi元钱,
但是这次交换会浪费Ti的时间.
doc希望可以在最短的时间内换到M元钱(其实是可以大于M的, 因为doc可以存私房钱呢), 否则学姐会生气的!


【题目分析】
无意中发现了这样一道题目,原题解出自学长的博客【魔法传送门
但是看不懂他的题解(看了一眼没看懂),然而整个网上只有他一个人的题解(还有一个是流氓网站用爬虫抄的)。(线段树解法)
然后自己来思考这道题目好了。
其实画到数轴上就是一个区间转移到一个值。那么为了保证过程的最优,可以把区间抽象成最左边的一个点,那么区间左端端点到一个值连一条边权为时间的边。再考虑到钱较多时可以通过少部分钱的状况进行转移,那么就可以把每个点向左面的点连一条边权为0的点,跑SPFA就可以了。
由于数据过大需要离散化,并且需要开long long。
(要不是网上没有好的题解我是不会写的)


【代码】

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
int T,n,m;
struct node{int v,r,t;}a[100001];
ll dis[300001],inf;
int inq[300001];
int h[300001],ne[1000001],to[1000001],w[1000001],en=0;
int ls[500001],top=0,kas=0;
void add(int a,int b,int c)
{
    ne[en]=h[a];
    to[en]=b;
    w[en]=c;
    h[a]=en++;
}
void spfa()
{
    memset(dis,0x3f,sizeof dis);
    inf=dis[0];
    inq[1]=1; dis[1]=0;
    queue<int>q;
    q.push(1);
    while (!q.empty())
    {
        int x=q.front(); q.pop(); inq[x]=0;
        for (int i=h[x];i>=0;i=ne[i])
        {
            if (dis[to[i]]>dis[x]+w[i])
            {
                dis[to[i]]=dis[x]+w[i];
                if (!inq[to[i]])
                {
                    q.push(to[i]);
                    inq[to[i]]=1;
                }
            }
        }
    }
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        memset(h,-1,sizeof h); en=0;
        scanf("%d%d",&n,&m); top=0;
        for (int i=1;i<=n;++i)
        {
            scanf("%d%d%d",&a[i].v,&a[i].r,&a[i].t);
            if (a[i].v>m) a[i].v=m;
            if (a[i].r>m) a[i].r=m;
            ls[++top]=a[i].v;
            ls[++top]=a[i].r;
        }
        sort(ls+1,ls+top+1);
        top=unique(ls+1,ls+top+1)-ls-1;
        for (int i=1;i<=n;++i)
        {
            a[i].v=lower_bound(ls+1,ls+top+1,a[i].v)-ls;
            a[i].r=lower_bound(ls+1,ls+top+1,a[i].r)-ls;
            add(a[i].r,a[i].v,a[i].t);
        }
        for (int i=2;i<=top;++i) add(i,i-1,0);
        spfa();
        printf("Case #%d: %lld\n",++kas,dis[top]==inf?-1:dis[top]);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值