首页 > 代码库 > CodeVS 1020孪生蜘蛛

CodeVS 1020孪生蜘蛛

  虽然最近最短路写的挺熟练的,但这道题还是坑了我两个小时。。

  题目大意:在一个无向图里找两个结点使在除了这两个结点以外的任意一个结点到这两个结点的权值最小。(距离为出发结点到两     个结点的最小权值)。

  算法:Floyd+枚举(SPFA蜜汁TLE。。)技术分享

 

 

  技术分享

 

  

  

  首先这道题读了好几遍都不知道它要求什么(题意好迷啊..),一直不明白什么叫最坏情况下的最优解,按自己的理解打了spfa,交    上去全wa。。于是按着wa的数据手动画了个图,然后跟着答案去推,才发现是求一波最短路再枚举两个点找最小值。。重新写了后把数据pia上去,(诶诶诶,这数据怎么读不完啊。。),突然发现读入n和后面并没有什么关系,n是结点数,说了n是通道数一眼过去明明就是边数啊。。

  交上去A了一个点。。(我的代码向来只能过样例。。),发现问题后突然发现SPFA写起来超级麻烦,因为SPFA用一个一维数组记录最短路,其实可以直接Floyd用二维记录简单多了。。(我好像写复杂了,算了,懒得重新打。。),于是写出来的spfa丑到爆炸,交上去蜜汁tle,懒得再查这个又臭又长的代码,直接花十几分钟敲了个Floyd交上去)。。AC。。

  出题人搞了好多坑点,我只想问问这些有意思吗。。题目都说不清楚啊。。

  下面大概讲讲正解思路,Floyd预处理出任意两个结点的距离,最坏情况是指每两个结点的最坏情况为两个结点到距离最远的点的权值,枚举下去再在这些权值中找出最小值,也就是每次枚举维护最小值,再把结点序号记录下来就是答案了。。

  由于蒟蒻太弱,写出来的SPFA又臭又长,各位看了可能感到身体不适,所以谨慎点开。(如果有兴趣的神犇还是帮蒟蒻看看为何tle..) 呃。。pia代码。

技术分享
 1 //蒟蒻的代码真的又臭又长。
 2 const maxp=10000;
 3 var
 4   t,n,maxx,i,j,ans1,ans2,minn,maxn,cost,k,p:longint;
 5   a,b:array[1..maxp,0..maxp]of longint;
 6   d,l,num,sum:array[1..maxp]of longint;
 7   v:array[1..maxp]of boolean;
 8   dist:array[1..maxp] of longint;
 9   f:array[1..maxp,1..maxp]of boolean;
10   head,tail:longint;
11 function max(a,b:longint):longint; //最大值
12 begin
13   if a>b then exit(a)
14   else exit(b);
15 end;
16 function min(a,b:longint):longint;//最小值
17 begin
18   if a<b then exit(a)
19   else exit(b);
20 end;
21 procedure init; //读入
22   var
23     i,j,x,y,z:longint;
24   begin
25    readln(n);
26   while not eoln do begin//因为是读入若干行所以用eof或eoln,但eof要转文件到记事本才可以看到结果,用eoln便于调试
27     readln(x,y,z);
28       inc(l[x]); inc(l[y]);//l数组记录结点是否出现及序号,其实好像没必要
29       if x>maxx then maxx:=x;
30       if y>maxx then maxx:=y;//找最大值便于枚举
31     inc(b[x,0]); b[x,b[x,0]]:=y; a[x,y]:=z;
32     inc(b[y,0]); b[y,b[y,0]]:=x; a[y,x]:=z;
33   end;
34 end;
35 procedure spfa(s:longint);//spfa大法好
36 var
37   i,j,now,sum:longint;
38 begin
39   fillchar(d,sizeof(d),0);
40   fillchar(v,sizeof(v),false);
41   for j:=1 to n do
42     dist[j]:=maxlongint;
43     dist[s]:=0; v[s]:=true; d[1]:=s;
44     head:=1; tail:=1;
45     while head<=tail do begin
46       now:=d[head];
47       for i:=1 to b[now,0] do
48         if (dist[b[now,i]]>dist[now]+a[now,b[now,i]]) then begin
49           dist[b[now,i]]:=dist[now]+a[now,b[now,i]];
50           if not v[b[now,i]] then begin
51             inc(tail);
52             d[tail]:=b[now,i];
53             v[b[now,i]]:=true;
54           end;
55         end;
56         v[now]:=false;
57         inc(head);
58       end;
59   end;
60 begin
61   fillchar(f,sizeof(f),true);//初始化
62   init;
63   for i:=1 to maxx do
64     if l[i]>0 then begin
65        inc(t);
66        num[t]:=i;
67     end;//把所有结点序号搞到num数组里面,比较方便
68     minn:=maxlongint;//找最小值记得初始化
69     //for i:=1 to n do
70       //write(num[i],  );
71   for i:=1 to n do
72     for j:=1 to n do
73       if num[i]<>num[j] then begin  //两个结点不能相同
74         spfa(num[i]); //以第一个结点开始求它到每个结点的距离
75         for k:=1 to n do
76           sum[k]:=dist[k];//把第一个结点的距离记录到sum数组,因为下      面一个spfa会更新dist数组
77           spfa(num[j]);//以第二个结点开始求它到每个结点的距离
78         maxn:=-maxlongint;//初始化啦
79         for k:=1 to n do
80           if (num[k]<>num[i])and(num[k]<>num[j]) then//出发结点与目标结点不能是同一个点   maxn:=max(maxn,min(sum[num[k]],dist[num[k]]));//找距离最远的点
81             if maxn<minn then begin
82               minn:=maxn;
83               ans1:=num[i]; ans2:=num[j];
84             end;//维护最小值,更新答案。
85           end;
86       write(ans1, ,ans2);//输出答案
87 end.
View Code

 

  呃。。下面Floyd正解?。。

  

技术分享
 1 var
 2   n,x,y,z,i,j,k,maxn,minn,ans1,ans2:longint;
 3   cost:array[1..10001,1..10001]of longint;//cost数组记录最短路
 4 function max(a,b:longint):longint;//最大值
 5 begin
 6   if a>b then exit(a)
 7   else exit(b);
 8 end;
 9 function min(a,b:longint):longint;//最小值
10 begin
11   if a<b then exit(a)
12   else exit(b);
13 end;
14 begin
15   readln(n);
16   for i:=1 to n do
17     for j:=1 to n do
18       cost[i,j]:=23333333;//初始化因为maxlongint会炸,于是搞一个灰常大的数。。
19   while not eoln do begin
20     readln(x,y,z);
21     cost[x,y]:=z;
22     cost[y,x]:=z;//无向图要建反向边。
23   end;
24   for k:=1 to n do begin //Floyd咯。
25     for i:=1 to n do
26       if i<>k then
27       for j:=1 to n do
28         if (i<>j)and(j<>k) then begin
29           if cost[i,j]>cost[i,k]+cost[j,k] then cost[i,j]:=cost[i,k]+cost[j,k];
30   end;
31 end;
32       minn:=maxlongint;
33   for i:=1 to n do
34     for j:=1 to n do
35       if i<>j then begin //枚举两个结点且不为同一个结点
36         maxn:=-maxlongint;
37         for k:=1 to n do
38           if (i<>k)and(j<>k) then maxn:=max(maxn,min(cost[i,k],cost[j,k]));//结点不重复找距离最远的结点
39           if maxn<minn then begin
40             minn:=maxn;
41             ans1:=i; ans2:=j;
42           end;//维护最小值,更新答案。
43         end;
44     write(ans1, ,ans2);//输出答案。
45 end.
View Code

 

这个故事告诉我萌:算法不用高大上,暴力也能出奇迹!!!

 

 

 

  

CodeVS 1020孪生蜘蛛