描述 Description
我们把火焰巨魔所处的位置抽象成一张有向图,他的位置就是1号点位,目的就是走到第N号点位,因为小火人会裂嘛,所以我们可以看做每走一条路,小火人的数量都会加倍,而每条路上的敌人有多强,会消耗多少小火人c[i]也会给出(c[i]为负值);当然有些时候路上也会遇到魔法泉之类的东西,这时候就可以补充一些小火人咯(c[i]为正值)。如果小火人死光了,那么火焰巨魔也就可以看做是挂了,毕竟智力型英雄就是脆啊。希望你帮助火焰巨魔用最少的初始小火人逃离这次屠杀。
输入格式 InputFormat
第一行两个数N(<=50000),M(<=100000)表示点位数与边数。一下M行,每行三个数a,b,c表示a,b两点间的边权是c(|c|<=10000)
输出格式 OutputFormat
输出仅一个整数,表示最小初始小火人数。
样例输入 SampleInput
5 4 1 2 -3 1 3 -6 3 4 1 4 5 -9
样例输出 SampleOutput
4
数据范围和注释 Hint
初始小火人为4个,到3点剩2个,到4变成5个,到5剩1个。所以初始最少为4,更少的小火人是不足以走到5号点位的。
题解
这道题有一点点恶心,不过还好。spfa倒着做,注意当dis[i]<1时,dis[i]=1。代码如下
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
int n,m,zz=0,head[50002];
struct bian
{int to,nx,l;} e[200002];
int q[50002],dis[50002];
bool pd[50002];
void insert(int x,int y,int z)
{
zz++; e[zz].to=x; e[zz].l=z; e[zz].nx=head[y]; head[y]=zz;
}
int calcu(int x)
{
if(x%2!=0) x=x+1;
x=x/2;
return x;
}
void spfa()
{
memset(pd,false,sizeof(pd));
memset(dis,127/3,sizeof(dis));
int t=0,w=1;
q[0]=n; pd[n]=true; dis[n]=1;
while(t!=w)
{pd[q[t]]=false;
int p=q[t],i=head[p]; t=t%n+1;
while(i)
{int s=calcu(dis[p]-e[i].l);
if(s<dis[e[i].to])
{dis[e[i].to]=s;
if(dis[e[i].to]<1) dis[e[i].to]=1;
if(!pd[e[i].to])
{pd[e[i].to]=true; q[w]=e[i].to; w=w%n+1;}
}
i=e[i].nx;
}
}
printf("%d\n",dis[1]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{int x,y,z;
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
}
spfa();
return 0;
}