Trick
【题目描述】
暴躁的稻草人,最终以自爆来给我们的队伍致命一击,全队血量见底,稻草人也一分为二。还好我们有雨柔妹子,瞬间精力回满。不过事后姜小弟和龙腹黑就开始了报复。
他们读取存档,将若干暴躁的稻草人活捉。然后将它们放到一个迷宫的入口。迷宫是有向图。此刻暴躁的稻草人们在1号位置,而迷宫出口在n号位置。因为稻草人会自爆,所以他每经过一条路数量就会加倍。每条路上有敌人,会消耗稻草人c[i](c[i]为负值);当然有些时候路上也会遇到止血草之类的东西,这时候就可以补充一些稻草人咯(c[i]为正值)。如果小稻草人死光了,那么稻草人也就可以看做是挂了。希望你帮助稻姜龙二人算出用最少的初始稻草人使其能够走出迷宫。
【输入格式】
第一行两个数N(<=50000),M(<=100000)表示点位数与边数。
以下M行,每行三个数a,b,c表示从a到b两点间的边权是c(|c|<=10000)
【输出格式】
输出仅一个整数,表示最小初始稻草人数。(在 [1,10000] 之间)
【输入样例】
5 4
1 2 -3
1 3 -6
3 4 1
4 5 -9
【输出样例】
4
首先,他给出答案的范围了,所以可以二分答案。
二分一开始有几个,然后跑最长路,看看能不能到头。
并且,如果遇到了环,则稻草人可以无限增加,所以可以直接得到答案,但还要继续二分,因为他让求最小的。
不过,还有第二种思路:可以发现,当用最少的稻草人开始走的时候,到达终点,一定只剩一个。
所以,倒着搜,就可以了。
二分答案(魂之挽歌)
program test2;
const dd=100000;
type bian=record
y,l,next:longint;
end;
var a:array[0..100010]of bian;
dist:array[0..50010]of int64;
v:array[1..50000]of boolean;
d:array[0..100000]of longint;
g:array[0..50000]of longint;
s:array[0..50001]of longint;
i,j,m,n,x,y,l,ans:longint;
function spfa(k:longint):boolean;
var t,w,i,x:longint;
begin
fillchar(dist,sizeof(dist),0);
fillchar(v,sizeof(v),0);
fillchar(s,sizeof(s),0);
t:=0;w:=1;d[w]:=1;v[1]:=true;dist[1]:=k;
s[1]:=1;
while t<>w do
begin
t:=(t+1)mod dd;x:=d[t];i:=g[x];
while i<>0 do
begin
if dist[a[i].y]<dist[x]*2+a[i].l then
begin
dist[a[i].y]:=dist[x]*2+a[i].l;
inc(s[a[i].y]);
if s[a[i].y]>n then exit(true);
if not v[a[i].y] then
begin
v[a[i].y]:=true;
w:=(w+1)mod dd;
d[w]:=a[i].y;
end;
end;
i:=a[i].next;
end;
end;
if dist[n]>0 then exit(true);
exit(false);
end;
procedure find(l,r:longint);
var mid:longint;
begin
if l>r then exit;
mid:=(l+r)shr 1;
if spfa(mid) then
begin
ans:=mid;
find(l,mid-1);
end
else find(mid+1,r);
end;
begin
assign(input,'trick.in');reset(input);
assign(output,'trick.out');rewrite(output);
readln(n,m);
for i:=1 to m do
begin
readln(x,y,l);
a[i].y:=y;
a[i].l:=l;
a[i].next:=g[x];
g[x]:=i;
end;
find(1,10000);
writeln(ans);
close(input);close(output);
end.
倒着推(Ray)
program lonely;
const
maxn=100010;
type
nod=record
x,y,len,next:longint;
end;
var
map:array[0..100010] of nod;
first:array[0..50000] of longint;
que:array[0..100010] of longint;
dist:array[0..50010] of int64;
v:array[0..50010] of boolean;
temp,head,tail,tot,x,y,len,t,i,n,m:longint;
begin
assign(input,'trick.in');
reset(input);
assign(output,'trick.out');
rewrite(output);
readln(n,m);
for i:=1 to m do
begin
readln(y,x,len);
len:=-len;
map[i].x:=x;map[i].y:=y;map[i].len:=len;
map[i].next:=first[x];first[x]:=i;
end;
fillchar(que,sizeof(que),0);
fillchar(v,sizeof(v),false);
filldword(dist,sizeof(dist)>>2,maxlongint>>1);
head:=0;tail:=1;
que[tail]:=n;
dist[n]:=1;
v[n]:=true;
while head<>tail do
begin
inc(head);
if head>maxn then head:=1;
x:=que[head];
t:=first[x];
while t<>0 do
begin
y:=map[t].y;
temp:=dist[x]+map[t].len;
if ((temp-1) div 2+1<dist[y])and(dist[x]>0)and(dist[y]>1) then
begin
dist[y]:=(temp-1) div 2+1;
if dist[y]<0 then dist[y]:=1;
if not v[y] then
begin
v[y]:=true;
inc(tail);
if tail>maxn then tail:=1;
que[tail]:=y;
end;
end;
t:=map[t].next;
end;
v[x]:=false;
end;
writeln(dist[1]);
close(input);
close(output);
end.