Shortest Path
You are given the graph and several queries about the shortest path between some pairs of vertices.
The first line contains two integer n
In the next m
The sum of values of m
1 10 2 2 4 5 7 8 10 1 5 3 1
7
题意:
给出1-n,n 个数字,代表n 个顶点,每个顶点到达其他顶点的距离是两个顶点对应的数字的差值,现在新加了三条边,每条边的距离都是1,并且给出新加边连接的顶点
后面有m次查询,每次查询给出两个顶点,求两点间最短距离,计算最短距离和查询的编号(查询编号从1开始)乘积的累加值。
题解:
看题目发现明显是多源最短路,但是直接跑多源的最短的floyd算法,肯定超时!、
题目给出了很好的前提条件:在新加入边之前,所有的顶点之间的最短路程,就是他们的编号的差值(当然是绝对值)!
那么现在单独研究这新加的三条边:
新边加入后,肯定引起最短路变化,但是只是影响了一部分,不必要对那些没影响的顶点进行最短路更新的操作
所以,完全可以只在新加入的几个顶点之间跑一次floyd 算法,求出这几个点之间的最短路的最短的路,然后在计算某两个点的最短路时,跑一次动态的最短路floyd更新,枚举这几个点对最短路径的影响,就可以得到任意两点的最短路了!
另外的技巧就是(个人感觉算是离散化),跑局部最短路的时候,用下标代替顶点进行更新!
个人心得:
第一次见到这样的题目,感觉真的是涨见识了,原本全是自己会的东西,但是根据题目条件限制,竟然可以这样灵活的变动,差点认不出来了...
确实学什么东西都是要深刻理解其中的本质,这是能灵活运用知识的前提,自己还要学的东西还有很多,继续努力吧!!!!
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,x[6]={0},dis[6][6]={0};
scanf("%d%d",&n,&m);
for(int i=0;i<6;++i)//三条边,六个点
{
scanf("%d",&x[i]);
}
for(int i=0;i<6;++i)//新加的三条边的原始距离
{
for(int j=0;j<i;++j)
{
dis[i][j]=dis[j][i]=abs(x[i]-x[j]);
}
}
for(int i=0;i<6;i+=2)//新加的边
{
dis[i][i+1]=dis[i+1][i]=1;
}
for(int i=0;i<6;++i)//三个点跑floyd最短路算法
{
for(int j=0;j<6;++j)
{
for(int k=0;k<6;++k)
{
dis[j][k]=min(dis[j][k],dis[j][i]+dis[i][k]);
}
}
}
long long ans=0;
for(int i=1;i<=m;++i)
{
int a,b;
scanf("%d%d",&a,&b);
int len=abs(a-b),mod=1e9+7;
for(int j=0;j<6;++j)
{
for(int k=0;k<6;++k)
{
int tp=abs(a-x[j])+abs(b-x[k])+dis[j][k];//暴力枚举
len=min(tp,len);
}
}
ans=(ans+(long long)i*len%mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}