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<=5000,1<=M<=200000,1<=E<=107,1<=ei<=E(ei∈R) 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;
}