城市交通费
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 }
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 const int N=250+1,inf=(1<<30)-1; 7 int head[N],p[N],dist[N][N],pp[N][N],cnt=0; 8 bool have_searched[N],inq[N]; 9 queue<int>q; 10 struct Edge{ 11 int to,d,link; 12 Edge(){to=0;d=inf;link=-1;} 13 }e[N<<1]; 14 void insert(int from,int to,int dis) 15 { 16 cnt++; 17 e[cnt].link=head[from];head[from]=cnt; 18 e[cnt].to=to;e[cnt].d=dis; 19 } 20 void spfa(int begin,int n) 21 { 22 if(have_searched[begin])return; 23 have_searched[begin]=true; 24 25 memset(inq,0,sizeof(inq)); 26 while(!q.empty())q.pop(); 27 28 int (&dis)[N]=dist[begin],(&boom)[N]=pp[begin]; 29 for(int i=1;i<=n;i++)dis[i]=inf;dis[begin]=0; 30 31 q.push(begin);inq[begin]=true; 32 while(!q.empty()) 33 { 34 int x=q.front();q.pop(); 35 inq[x]=false; 36 for(int it=head[x];e[it].link!=-1;it=e[it].link) 37 { 38 int y=e[it].to; 39 if(dis[x]+e[it].d+max(boom[x],p[y]) < dis[y]+boom[y]) 40 { 41 dis[y]=dis[x]+e[it].d; 42 boom[y]=max(boom[x],p[y]); 43 if(!inq[y]){q.push(y);inq[y]=true;} 44 } 45 } 46 } 47 } 48 int main() 49 { 50 memset(pp,0,sizeof(pp)); 51 memset(head,-1,sizeof(head)); 52 memset(have_searched,0,sizeof(have_searched)); 53 54 int n,m,Q; 55 scanf("%d %d %d",&n,&m,&Q); 56 for(int i=1;i<=n;i++)scanf("%d",&pp[i][i]); 57 for(int i=1;i<=m;i++) 58 { 59 int a,b,w; 60 scanf("%d %d %d",&a,&b,&w); 61 insert(a,b,w);insert(b,a,w); 62 } 63 for(int i=1;i<=Q;i++) 64 { 65 int x,y; 66 scanf("%d %d",&x,&y); 67 spfa(x,n); 68 printf("%d",dist[x][y]+pp[x][y]); 69 if(i!=Q)printf("\n"); 70 } 71 return 0; 72 }