1 10 2 2 4 5 7 8 10 1 5 3 1
7
题意:给你一条n个点组成的链,相邻两点的距离为1,再给你三条边,这三条边的端点都是链上的点,且每一条的距离为1。有m个询问,问你对于每两个点,从一个端点到另一个端点的最近距离是多少。
思路:可以先初始化3条边中6个点两两之间的最短距离,这个可以用floyd做,那么对于每一个询问,两个点x1,x2的最短距离为不经过任何点,或者经过3条边中的某些边,又因为我们已经初始化出3条边中任意两个点的最短距离,所以我们只要枚举a,b,即x1到a,a到b,再b到x2的最近距离。这一题floyd初始化时关键,如果每次直接8个点floyd时间复杂度就爆了。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<bitset> #include<algorithm> using namespace std; typedef long long ll; typedef long double ldb; #define inf 1000000007 #define pi acos(-1.0) #define MOD 1000000007 int dist[10][10]; void floyd() { int i,j,k; for(k=1;k<=6;k++){ for(i=1;i<=6;i++){ for(j=1;j<=6;j++){ if(dist[i][j]>dist[i][k]+dist[k][j]){ dist[i][j]=dist[i][k]+dist[k][j]; } } } } } int main() { int n,m,i,j,T,k; int x[10]; int a1,b1,a2,b2,a3,b3; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); scanf("%d%d%d%d%d%d",&x[1],&x[2],&x[3],&x[4],&x[5],&x[6]); for(i=1;i<=6;i++){ for(j=1;j<=6;j++){ dist[i][j]=abs(x[i]-x[j]); } } dist[1][2]=dist[2][1]=min(dist[1][2],1); dist[3][4]=dist[4][3]=min(dist[3][4],1); dist[5][6]=dist[6][5]=min(dist[5][6],1); floyd(); ll sum=0; for(k=1;k<=m;k++){ scanf("%d%d",&x[7],&x[8]); int ans=abs(x[7]-x[8]); for(i=1;i<=6;i++){ for(j=1;j<=6;j++){ ans=min(ans,abs(x[7]-x[i] )+abs(x[8]-x[j])+dist[i][j] ); ans=min(ans,abs(x[7]-x[j] )+abs(x[8]-x[i])+dist[i][j] ); } } sum=(sum+(ll)ans*(ll)k)%MOD; //printf("%d\n",floyd()); } printf("%lld\n",sum); } return 0; }