背景
TYVJ2月月赛第一道
巨魔家族在某天受到了其他种族的屠杀,作为一个英雄,他主动担任了断后的任务,但是,在巨魔家族整体转移过后,火焰巨魔却被困住了,他出逃的方式也只有召唤小火人这一种方式,所以请你帮助他。
巨魔家族在某天受到了其他种族的屠杀,作为一个英雄,他主动担任了断后的任务,但是,在巨魔家族整体转移过后,火焰巨魔却被困住了,他出逃的方式也只有召唤小火人这一种方式,所以请你帮助他。
描述
我们把火焰巨魔所处的位置抽象成一张有向图,他的位置就是1号点位,目的就是走到第N号点位,因为小火人会裂嘛,所以我们可以看做每走一条路,小火人的数量都会加倍,而每条路上的敌人有多强,会消耗多少小火人c[i]也会给出(c[i]为负值);当然有些时候路上也会遇到魔法泉之类的东西,这时候就可以补充一些小火人咯(c[i]为正值)。如果小火人死光了,那么火焰巨魔也就可以看做是挂了,毕竟智力型英雄就是脆啊。希望你帮助火焰巨魔用最少的初始小火人逃离这次屠杀。
输入格式
第一行两个数N(<=50000),M(<=100000)表示点位数与边数。
一下M行,每行三个数a,b,c表示a,b两点间的边权是c(|c|<=10000)
一下M行,每行三个数a,b,c表示a,b两点间的边权是c(|c|<=10000)
输出格式
输出仅一个整数,表示最小初始小火人数。
测试样例1
输入
5 4
1 2 -3
1 3 -6
3 4 1
4 5 -9
输出
4
备注
初始小火人为4个,到3点剩2个,到4变成5个,到5剩1个。
所以初始最少为4,更少的小火人是不足以走到5号点位的。from wsd TYVJ月赛出题组
题解
从最后一个点倒着想 设最后一个点剩一个然后倒着推
把边反过来 加减反过来 乘变成除 当一个点i的d[i]小于1时 把他变成1 注意除法向上取整
//http://new.tyvj.cn/p/1176
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 50001
#define inf 1<<29
using namespace std;
int n,m,head[N],d[N];
int flag[N],cnt;
queue<int>q;
struct node{int to,w,next;}e[100001];
void insert(int x,int y,int z){
e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt;
}
int get(int n){//向上取整 因为只有向上才可以满足条件 不一定最优解最后一个点剩下的就是1
if(n%2!=0)n++;
return n/2;
}
void spfa(){
for(int i=1;i<=n;i++)
d[i]=inf;
d[n]=1;//注意 最后一个点最少剩一个
flag[n]=1;
q.push(n);
while(!q.empty()){
int k=q.front();
q.pop();flag[k]=0;
for(int i=head[k];i;i=e[i].next){
int kk=e[i].to;
if(d[kk]>get(d[k]+e[i].w)){
d[kk]=get(d[k]+e[i].w);
if(d[kk]<1)d[kk]=1;
if(!flag[kk]){
flag[kk]=1;
q.push(kk);
}
}
}
}
}
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(y,x,-z); //设到终点的时候剩一个 然后倒着做 操作反过来 加变减减变加
}
spfa();
printf("%d",d[1]);
return 0;
}