您的位置:首页 > 其它

Vijos P1901 学姐的钱包

2016-11-09 21:38 246 查看
描述

学姐每次出门逛街都要带恰好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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: