1 10 2 2 4 5 7 8 10 1 5 3 1
7
题意:有一条长度为n的链. 节点i和i+1之间有长度为1的边. 现在又新加了3条边, 每条边长度都是1. 给出m个询问, 每次询问两点之间的最短路.
开始的时候想的是把开始六个点预处理了,再把询问的两个点加入跑Floyed,但是这样复杂度太高,会tle。
因为前六个点之间的边权关系永远不会变,所以先对前六个个点跑一遍Floyed,然后输入一个询问处理一个询问,询问u->v的最短路,遍历所有可能的情况,即u->i->j->v,还有u直线到v的距离,一共37种情况,取最小就行了,所以总的复杂度只有O(6^2 * m)。
CODE
#include <iostream> #include <string.h> #include <algorithm> #include <stdlib.h> using namespace std; typedef long long LL; const long long mod = 1e9+7; const long long INF = 777777777; LL a[20]; ///记录6个点 LL Map[20][20]; ///记录地图 LL ans; ///答案 void INIT() ///初始化 { ans = 0; for(LL i = 0;i < 10;i++) { for(LL j = 0;j < 10;j++) { Map[i][j] = INF; } } } int main() { LL T; scanf("%I64d",&T); while(T--) { INIT(); LL n,m; scanf("%I64d%I64d",&n,&m); for(LL i = 1; i <= 6; i++) ///输入6个点 { scanf("%I64d",&a[i]); for(LL j = i-1;j >= 1;j--) ///两个点之间的直线距离 { LL t1 = a[i],t2 = a[j]; Map[i][j] = Map[j][i] = abs(t1-t2); } } for(LL i = 1; i <= 6; i++) ///第12 34 56点之间距离为1 { if(i%2 == 0) { Map[i][i-1] = Map[i-1][i] = 1; } } for(LL i = 1;i <= 6;i++) ///Floyed for(LL j = 1;j <= 6;j++) for(LL k = 1;k <= 6;k++) Map[j][k] = min(Map[j][k],Map[j][i]+Map[i][k]); for(LL i = 1;i <= m;i++) { LL u,v; scanf("%I64d %I64d",&u,&v); LL t = abs(u-v); for(int k = 1; k <= 6 ;k++) ///u->i->j->v所有36种可能跑一遍取最小 for(int j = 1; j <= 6; j++) { LL tmp = abs(u-a[k])+Map[k][j]+abs(a[j]-v); t = min(t,tmp); } ans = (ans%mod+i*t%mod)%mod; } printf("%I64d\n",ans); } return 0; }