TYVJ1467 通往聚会的道路

【题目描述】

Candy共有t个朋友住在不同的区域。小镇有m条道路,小镇的神奇之处在于其中的p1条道路只会在你走过区域的的个数为奇数时候开启,p2道路只会在你走过区域的个数为偶数的时候开启,剩下的道路一直都会开启。并且,所有的道路只能够单向通过。飘飘乎居士希望知道在所有的好朋友中,谁离Candy最近?。

【输入文件】

第一行:两个正整数n m,表示共n个区域,m条道路           

接下来m行,每行三个正整数u v s表示u到v的单向道路,路程为s,其中第i条道路的编号为i。           接着一个整数p1以及p1个正整数odd[i],表示编号为odd[i]的道路只会在走过奇数个区域时开启。           

接着一个整数p2以及p2个正整数even[i],表示编号为even[i]的道路只会在走过偶数个区域时开启。           

接下来一个正整数 t           

紧接着t行,每行一个正整数h以及一个不超过10个字符长度的字符串na(且均有小写字母组成),表示在h区域居住着名字为na的人。

【输出文件】

第一行,即距离candy家最近的人的名字,数据保证有且只有一个人为最后的答案。  

第二行,该人到candy家的距离。     

如果存在多解,则输入名字中字典序较小的一人。

【输入样例】

4 5

1 2 2

3 4 2

2 4 4

1 3 1

2 3 1

1 4

1 2

2

2 violethill

1 pink

【输出样例】 

violethill

4

 

【题目分析】

这是一道比较基础的图论题目,用dist[i,0..1]来表示走到第i个点时走过了偶数(0)或奇数(1)个点时的最短时间,进行SPFA

但是,源点有多个,对每一个都跑一边SPFA,时间复杂度为O(m*t),显然太高了。

分析题目,发现终点只有1个,这样就从终点开始,把所有有向边都反过来,这样就不用t次SPFA了。

但是,问题又出现了,从终点到i走的点的个数与从某源点走的点的个数奇偶性不一定相同,一次SPFA无法处理。

我们发现,从终点走奇数个点到达的点j,j到终点的路径上每一个点与j之间的点数和其与终点之间的点数的奇偶性是不同的,反之,如果是从终点走过偶数个点走到的店,其奇偶性相同。

于是跑一边SPFA后,把边的奇偶性反过来再跑一遍就行了。

注意处理一个边在奇偶中都出现的情况。

【代码实现】

Code
  1 program tyvj1467;
2 type bian=record
3 y,o,next,l:longint;
4 c:boolean;
5 end;
6 var a:array[0..100000]of bian;
7 g:array[0..10000]of longint;
8 dist:array[0..10000,0..1]of longint;
9 v:array[0..10000,0..1]of boolean;
10 d,o:array[0..1000000]of longint;
11 b:array[0..100000]of longint;
12 s:array[0..100000]of ansistring;
13 i,j,m,n,k,x,y,p,q,e,l,tmp:longint;
14 procedure spfa;
15 var t,w,i,j,k,x,e,y,ee:longint;
16 begin
17 fillchar(dist,sizeof(dist),63);
18 dist[n,0]:=0;v[n,0]:=true;t:=1;w:=1;d[1]:=n;o[1]:=0;
19 while t<=w do
20 begin
21 x:=d[t];e:=o[t];
22 inc(t);
23 v[x,e]:=false;
24 i:=g[x];ee:=1-e;
25 while i<>0 do
26 begin
27 if a[i].o=e then
28 begin
29 i:=a[i].next;
30 continue;
31 end;
32 y:=a[i].y;
33 if dist[y,ee]>dist[x,e]+a[i].l then
34 begin
35 dist[y,ee]:=dist[x,e]+a[i].l;
36 if not v[y,ee] then
37 begin
38 inc(w);
39 d[w]:=y;
40 o[w]:=ee;
41 end;
42 end;
43 i:=a[i].next;
44 end;
45 end;
46 end;
47 begin
48 readln(n,m);
49 for i:=1 to m do
50 begin
51 readln(x,y,l);
52 a[i].y:=x;
53 a[i].l:=l;
54 a[i].next:=g[y];
55 g[y]:=i;
56 a[i].o:=2;
57 end;
58 read(k);
59 for i:=1 to k do
60 begin
61 read(x);
62 a[x].o:=0;
63 end;
64 read(k);
65 for i:=1 to k do
66 begin
67 read(x);
68 if a[x].c then continue;
69 if a[x].o=0 then
70 begin
71 a[x].o:=2;
72 a[x].c:=true;
73 end
74 else a[x].o:=1;
75 end;
76 readln(p);
77 for i:=1 to p do
78 begin
79 readln(b[i],s[i]);
80 delete(s[i],1,1);
81 end;
82 spfa;
83 j:=1;
84 for i:=2 to p do
85 if (dist[b[i],1]<dist[b[j],1])or((dist[b[i],1]=dist[b[j],1])and(s[i]<s[j])) then j:=i;
86 k:=j;tmp:=dist[b[k],1];
87 for i:=1 to m do
88 begin
89 if a[i].o=2 then continue;
90 a[i].o:=1-a[i].o;
91 end;
92 spfa;
93 for i:=2 to p do
94 if (dist[b[i],0]<dist[b[j],0])or((dist[b[i],0]=dist[b[j],0])and(s[i]<s[j])) then j:=i;
95 if (dist[b[j],0]<tmp)or((dist[b[j],0]=tmp)and(s[j]<s[k])) then
96 begin
97 tmp:=dist[b[j],0];
98 k:=j;
99 end;
100 writeln(s[k]);
101 writeln(tmp);
102 end.


转载于:https://www.cnblogs.com/whitecloth/archive/2012/03/20/2408507.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值