2017青岛比赛第二题(亦或是最后一题?记不真切了),后天就青岛2018了。。。然而今天才会去年的题。。。
题目大意
有n个城市,编号1~n。其中 i 号城市的繁华度为 Pi,省内有 m 条可以
双向通行的高速公路,编号1~m。编号为 j 的高速公路连接编号为 Aj 和 Bj 的
两个城市, 经过这条公路的高速公路的费用是 Wj 。若从城市 x 出发到达某城市 Y,
除了需要交纳高速公路费用,还要交纳“城市建设费”(为从 x 到 y 所经过的所有
城市中繁华度的最大值,包括 x 和 y 在内)
现在有 Q 个询问,每个询问给出一组 X 和 Y,回答从 X 到 Y 所需要的
最低的交通费(高速公路费 + 城市建设费)
输入格式:
第一行:n,m,Q
l第二行:P1~Pn
接下来 m 行,每行3个正整数,第 j 行包含 Aj , Bj ,Wj
随后 Q 行每组二个正整数 X,Y,表示一组询问
n<=250,m<=2e4,Q<=1e4,Pi<=1e4,Wj<=2e3,保证任意两个城市可以互相到达
输出格式:
Q行,每行对应一个整数,即对应询问的答案
分析:此题乍一看似乎是 Floyd 算法的应用,但实际上用 Dijkstra 更好,可以将 “当前节点” 与 “标记节点” 捆绑起来。(但并不是说 Floyd 不能做,只是较麻烦,详见 能神带你飞 博客:https://www.cnblogs.com/nengshen/)
1 //Copyright(C)昤昽 2 //2018.05.20 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 using namespace std; 7 const int N=250+1,inf=(1<<30)-1; 8 int g[N][N],v[N],pp[N][N],p[N],dist[N][N];//,sd[N]; 9 void dijkstra(int begin,int n) 10 { 11 memset(v,0,sizeof(v)); 12 int (&d)[N]=dist[begin],(&boom)[N]=pp[begin]; 13 for(int i=1;i<=n;i++)d[i]=inf;d[begin]=0; 14 for(int i=1;i<=n;i++)boom[i]=0;boom[begin]=p[begin]; 15 for(int i=1;i<=n;i++) 16 { 17 int x,m=inf; 18 for(int y=1;y<=n;y++)if(!v[y] && d[y]+boom[y]<=m)m=d[x=y]+boom[y]; 19 v[x]=1; 20 for(int y=1;y<=n;y++) 21 if(g[x][y] && d[x]+g[x][y]+max(boom[x],p[y]) < d[y]+boom[y]) 22 { 23 d[y]=d[x]+g[x][y]; 24 boom[y]=max(boom[x],p[y]); 25 } 26 } 27 } 28 int main() 29 { 30 // freopen("cityFee.in","r",stdin); 31 // freopen("cityFee.out","w",stdout); 32 memset(g,0,sizeof(g)); 33 memset(p,0,sizeof(p)); 34 memset(pp,0,sizeof(pp)); 35 int n,m,Q; 36 scanf("%d %d %d",&n,&m,&Q); 37 for(int i=1;i<=n;i++)scanf("%d",&p[i]); 38 for(int i=1;i<=m;i++) 39 { 40 int a,b,d; 41 scanf("%d %d %d",&a,&b,&d); 42 g[a][b]=g[b][a]=d; 43 } 44 for(int i=1;i<=n;i++)dijkstra(i,n); 45 for(int i=1;i<=Q;i++) 46 { 47 int x,y; 48 scanf("%d %d",&x,&y); 49 printf("%d",dist[x][y]+pp[x][y]); 50 if(i!=Q)printf("\n"); 51 } 52 return 0; 53 }