[floyd][usaco.09.DEC.][jzyzoj1218][过路费]——floyd新姿势get

  这道题并没有1A,因为读入邻接矩阵的时候忘了处理重边。。。下面给出题面:

  

  最初看的时候以为纯粹的floyd是可以用的,然而发现并不可以,因为无法查找遍历的最大点,这时候需要转变思想:当你遍历i,j,k时,如何保证权值最大的点就在这三个点之间?我们是不是能将点重组一遍,让所有点按照权值大小排列呢?

  这样思路就有了:

  如果k从大到小排列的话,不能保证权值在i,j,k之间,因为更新过路径之后权值最大的点已经包含在路径中了。

  如果k从小到大排列的话,每次更新最短路,权值最大的点都会在i,j,k之间。

  所以我们可以按照这个思路,记录每个点的下标及权值,然后按照权值从小到大排序,所得到的序列就是k应该查找的顺序。

  另外处理边的时候需要将最短路与最短路加上最大点权值分开处理。

  代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 struct points{
 7     int v,p;
 8 }point[260];//v为点的值,p为点的坐标
 9 int a[260][260],n,m,k,c[260][260],cow[260];
10 bool mycmp(points x,points y)
11 {return x.v<y.v;}
12 void init()
13 {
14     scanf("%d%d%d",&n,&m,&k);
15     memset(a,0x3f,sizeof(a));
16     for (int i=1;i<=n;i++)
17     {
18         scanf("%d",&point[i].v);
19         a[i][i]=0;    c[i][i]=point[i].v;//点到自身的距离处理,c为边+最大点权值的值,a为边值
20         cow[i]=point[i].v;//另记录每个点的权值,方便查找
21         point[i].p=i;
22     }
23     int x,y,v;
24     for (int i=1;i<=m;i++)
25     {
26         scanf("%d%d%d",&x,&y,&v);
27         a[x][y]=min(a[x][y],v);//处理重边
28         a[y][x]=a[x][y];
29     }
30     sort(point+1,point+1+n,mycmp);//将点按照从小到大排序
31 }
32 
33 void floyd()
34 {
35     for (int x=1;x<=n;x++)
36     {
37         int k=point[x].p;
38         for (int i=1;i<=n;i++)
39             for (int j=1;j<=n;j++)
40             {
41                 a[i][j]=a[j][i]=min(a[i][k]+a[k][j],a[i][j]);//更新最短路
42                 c[i][j]=c[j][i]=min(c[i][j],a[i][j]+max(max(cow[i],cow[j]),cow[k]));//将当前求得最小值与最短路加上最大权值进行比较并更新
43             }
44     }
45 }
46 
47 int main()
48 {
49     freopen("add.in","r",stdin);
50     freopen("add.out","w",stdout);
51     memset(c,0x3f,sizeof(c));
52     init();
53     floyd();
54     int x,y;
55     for (int i=1;i<=k;i++)
56     {
57         scanf("%d%d",&x,&y);
58         printf("%d
",c[x][y]);
59     }
60     return 0;
61 }
AC代码

  这道题对于floyd的理解具有巨大帮助。

原文地址:https://www.cnblogs.com/hinanawitenshi/p/6558250.html