BZOJ 1975 魔法猪学院 k短路

82 篇文章 0 订阅
9 篇文章 0 订阅

Problem

Description

iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练。经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的;元素与元素之间可以互相转换;能量守恒……。 能量守恒……iPig 今天就在进行一个麻烦的测验。iPig 在之前的学习中已经知道了很多种元素,并学会了可以转化这些元素的魔法,每种魔法需要消耗 iPig 一定的能量。作为 PKU 的顶尖学猪,让 iPig 用最少的能量完成从一种元素转换到另一种元素……等等,iPig 的魔法导猪可没这么笨!这一次,他给 iPig 带来了很多 1 号元素的样本,要求 iPig 使用学习过的魔法将它们一个个转化为 N 号元素,为了增加难度,要求每份样本的转换过程都不相同。这个看似困难的任务实际上对 iPig 并没有挑战性,因为,他有坚实的后盾……现在的你呀! 注意,两个元素之间的转化可能有多种魔法,转化是单向的。转化的过程中,可以转化到一个元素(包括开始元素)多次,但是一但转化到目标元素,则一份样本的转化过程结束。iPig 的总能量是有限的,所以最多能够转换的样本数一定是一个有限数。具体请参看样例。

Input

第一行三个数 N、M、E 表示iPig知道的元素个数(元素从 1 到 N 编号)、iPig已经学会的魔法个数和iPig的总能量。 后跟 M 行每行三个数 si、ti、ei 表示 iPig 知道一种魔法,消耗 ei 的能量将元素 si 变换到元素 ti 。

Output

一行一个数,表示最多可以完成的方式数。输入数据保证至少可以完成一种方式。

Sample Input

4 6 14.9
1 2 1.5
2 1 1.5
1 3 3
2 3 1.5
3 4 1.5
1 4 1.5

Sample Output

3

Data Size

2<=N<=50001<=M<=2000001<=E<=1071<=ei<=EeiR 2 <= N <= 5000 , 1 <= M <= 200000 , 1 <= E <= 10 7 , 1 <= e i <= E ( e i ∈ R )

题外话

做了好久…一直WA一个点,好像是因为精度问题……double不太好调。然后借了 @Dimitry_L (早已 AC)的程序来对拍发现某些数据会差距很大,开始懵逼。于是,借了 @boshi (早已AC)的程序继续拍,发现和我的答案差别较小,还是有点担心。又上网翻出了 @tb (早已AC)的程序继续拍,和boshi的一致。于是开始拍……发现原来是扩展到n节点时的判断先后顺序有误……
然后开始改,改,突然发现bosh和tb貌似都没注意到 扩展到n节点就不再扩展 。改了下,再交,依然AC?原来是数据太水了(居然能骗到90分却总被卡一个点)。
后来我注意到,dalao们用的都是SPFA,只有我特别智障地看了看n和m的差距写了堆优化的dijkstra……作死技能++
第一次AC洛谷上 [NOI+/CTSC] 难度的题,也就是说洛谷各个难度等级的题目我都AC了至少一道题,感动中国QwQ,特此纪念!
最后,%%%tb!!!

Solution

在本题中,很明显,可以看出元素之间的转换就相当于在两个之间连有向边。要询问最多可以得到几份样本,那么就需要每次转换样本都最小,也就是相当于不断求1点到n点的之间的k短路问题,直到前k条路的总和sum>=maxx为止。
求k短路,用dijkstra/SPFA+A*,cnt记录到达t节点的次数。令g(x)表示已经走过的路,h(x)表示从x节点出发,走到t的最短路径,每次取出 g(x)+h(x) g ( x ) + h ( x ) 最小的节点扩展。当某次到达t节点时使得sum>=maxx,那么就输出cnt。
温馨提示(boshi says):bzoj上评测,用优先队列,且结构体中记录了f(x),g(x),h(x),v什么的会导致MLE,需要稍微压一下空间才能用优先队列。或者你可以选择手写堆。然而我选择用algorithm里面的有关heap的函数。

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
template <typename Tp> inline void read(Tp &x)
{
    x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
const int maxn=5010,maxm=200010,INF=0x3f3f3f3f;
const double eps=1e-12;
struct data{
    int v,nxt;
    double w;
}edge[maxm<<1],edge2[maxm<<1];
struct node{
    int v;
    double dis;
    bool operator >(const node &a) const
    {
        return dis>a.dis;
    }
}di[maxn<<4];
struct state{
    int v;
    double g,h;
    bool operator >(const state &a) const
    {
        return g+h>a.g+a.h; 
    }
}q[maxm<<3];
int n,m,num,p,cnt,head[maxn],head2[maxn];
bool vis[maxn];
double maxx;
double mindis[maxn];
inline void insert(int u,int v,double w)
{
    edge[++num].v=v;
    edge[num].w=w;
    edge[num].nxt=head[u];
    head[u]=num;
    edge2[num].v=u;
    edge2[num].w=w;
    edge2[num].nxt=head2[v];
    head2[v]=num;
}
void input()
{
    int u,v;
    double w;
    read(n),read(m);
    scanf("%lf",&maxx);
    for(int i=1;i<=m;i++)
    {
        read(u),read(v);
        scanf("%lf",&w);
        insert(u,v,w);
    }
}
void dijkstra(int x)
{
    p=0;
    for(int i=1;i<=n;i++)
      mindis[i]=INF;
    node index,now;
    mindis[x]=0;
    index.v=x;index.dis=0;
    di[++p]=index;
    while(p)
    {
        index=di[1];
        pop_heap(di+1,di+p+1,greater<node>());
        p--;
        if(vis[index.v])
          continue;
        vis[index.v]=true;
        for(int i=head2[index.v];i;i=edge2[i].nxt)
          if(mindis[edge2[i].v]>mindis[index.v]+edge2[i].w)
          {
            mindis[edge2[i].v]=mindis[index.v]+edge2[i].w;
            now.v=edge2[i].v;now.dis=mindis[edge2[i].v];
            di[++p]=now;
            push_heap(di+1,di+p+1,greater<node>());
          }
    }
}
void astar(int s,int t)
{
    p=0;
    state index,now;
    index.v=s;index.g=0;index.h=mindis[s];
    q[++p]=index;
    while(p)
    {
        index=q[1];
        pop_heap(q+1,q+p+1,greater<state>());
        p--;
        if(index.v==t)
        {
            maxx-=index.g+index.h;
            if(maxx<-eps)
              return ;
            cnt++;
            continue;
        }
        for(int i=head[index.v];i;i=edge[i].nxt)
        {
            now.v=edge[i].v;
            now.g=index.g+edge[i].w;
            now.h=mindis[now.v];
            q[++p]=now;
            push_heap(q+1,q+p+1,greater<state>());
        }
    }
}
int main()
{
    input();
    dijkstra(n);
    astar(1,n);
    printf("%d\n",cnt);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值