首页 > 代码库 > 习题:破坏基地(最短路+计数)

习题:破坏基地(最短路+计数)

                                                   破坏基地(tyvj2040)

描述

在Z国和W国之间一直战火不断。
好不容易,W国的间谍把完整的Z国的军事基地的地图到手了。
于是W国决定再次出击,一举击破Z国的防线。
W国认真研究了Z国的地形,发现Z国有N个军事基地,我们不妨编号成1..N,而且经过深刻研究,发现1号军事基地是资源补给基地,而N号军事基地是前线。
由于地形的缘故,只有M对军事基地两两可达,当然是有距离的。
此时W国的弹头紧缺,当下的弹头只能去毁灭一个军事基地。当然了,最重要的就是毁灭一个军事基地,使得资源补给基地与前线的最短距离发生变化。但是Z国也不是白痴,他们的资源补给基地与前线有着极高的防御力,所以W国只能去炸掉其余的N-2个基地,当然炸掉某个基地后,这个基地就不可达了。
于是问题就来了,炸掉哪些基地后会使得资源补给基地与前线的最短距离发生变化呢?
注:假若炸掉某个基地后,1号基地和N号基地不连通,那么我们也认为他们的最短距离发生了变化。

 

输入格式

输入数据第一行是两个正整数N,M,意义如题所述。
接下来M行,每行包括三个正整数x,y,d,表示有一条边连接x、y两个地点,其距离为d。
数据保证图是连通的。

 

输出格式

输出数据的第一行包含一个整数K,表示有K个基地可毁灭,且毁灭其中任意一个后,资源补给基地与前线的最短距离发生变化。
接下来K行,每行输出一个军事基地的编号,要求编号递增。
在wyl8899神犇的率领下,W国必胜!!!
因此一定不会存在K=0的情况。

 

测试样例1

输入

6 7
1 2 3
1 5 2
2 3 5
2 4 3
2 5 4
2 6 5
3 4 2
输出

1
2
备注

对于30%的数据,N<=100,M<=1,000;
对于60%的数据,N<=2,000,M<=20,000;
对于100%的数据,N<=10,000,M<=100,000,1<=d<=10,000;

 

分析:

图中可能存在多条最短路,显然当某个点在所有最短路上才是应选择的点。

于是我们分别从1和n求一次最短路,并统计从1到各点最短路条数f1和n到各点最短路条数f2,dis1[i]+dis2[i]=minlen,f1[i]*f2[i]=1到n最短路条数 说明i在所有最短路上,加入答案就行了。

代码:

技术分享
program hehe;
type
  point=^node;
   node=record
      x,v:int64; next:point;
   end;

var
  a:array[0..10000]of point;
  q:array[0..100000]of int64;
  dis,u,tot,r,b:array[0..10000]of int64;
  g:array[0..10000]of boolean;
  n,i,m,x,y,ans:longint; len,v:int64;
procedure add(x,y,v:longint);
var p:point;
begin
  new(p); p^.x:=y; p^.v:=v; p^.next:=a[x]; a[x]:=p;
end;
procedure spfa(s:longint);
var i,x,y,h,t:longint; p:point;
begin
  for i:=1 to n do begin dis[i]:=maxlongint*10; g[i]:=false; tot[i]:=0;end;
  g[s]:=true; dis[s]:=0; tot[s]:=1; h:=0; t:=1;  q[t]:=s;
  while h<t do
   begin
     inc(h); x:=q[h]; new(p); p:=a[x]; g[x]:=false;
     while p<>nil do
      begin
        y:=p^.x;
        if dis[x]+p^.v<dis[y] then
        begin
         dis[y]:=dis[x]+p^.v; tot[y]:=tot[x];
         if g[y]=false then
          begin
            inc(t); q[t]:=y; g[y]:=true;
          end;
        end
        else if dis[x]+p^.v=dis[y] then
         begin
           inc(tot[y],tot[x]);
           if g[y]=false then
           begin
            inc(t); q[t]:=y; g[y]:=true;
          end;
         end;
        p:=p^.next;
      end;
   end;
  if s=1 then
   begin len:=dis[n]; u:=dis; r:=tot;end;
end;
begin
  readln(n,m);
  for i:=1 to m do
   begin
     readln(x,y,v);
     add(x,y,v); add(y,x,v);
   end;
  spfa(1); spfa(n);
  for i:=1 to n do
   if (i<>1)and(i<>n) then
   if u[i]+dis[i]=len then if tot[i]*r[i]=tot[1] then begin inc(ans);b[ans]:=i; end;
  writeln(ans);
  for i:=1 to ans do writeln(b[i]);
end.
View Code

 

习题:破坏基地(最短路+计数)