P2966 [USACO09DEC] Cow Toll Paths G
copy来的题面
给定一个 点 边的双向图,第 条道路连接了 与 ,边权为 ,第 个点的点权为 。
给定 组询问,第 组询问求从 到 的路径的边权之和与点权的最大值的和的最小值。
可能有重边,但保证无自环。
对于 的数据,,,。
分析
一看,就知道是flyd,但本题的题面实在有点绕,英译中再译中一下,就是输出两点之间的最短路长度加上该条最短路径上的最大点权的最小值
分别以pos[i].id
和pos[i].w
记录点的编号和点权,从小到大排序。
处理时就先跑常规的最短路
int u=pos[i].id,v=pos[j].id,kk=pos[k].id;
flyd[u][v]=min(flyd[u][v],flyd[u][kk]+flyd[kk][v]);
由于已经排过序了,所以这里得转一下用pos[i].id
、pos[j].id
、pos[k].id
表示点。
最大点权比较时,注意不能只算这一个,因为只是中转点,所以也得算上。
代码部分
#include<bits/stdc++.h>
using namespace std;
const int maxn=552;
int n,m,q;
int flyd[maxn][maxn];
struct node {
int id,w;
} pos[maxn];
bool cmp(node x,node y) {
return x.w<y.w;
}
int ans[maxn][maxn];
int main() {
memset(ans,0x3f,sizeof(ans));
cin>>n>>m>>q;
for(int i=1; i<=n; i++) {
cin>>pos[i].w;
pos[i].id=i;
}
sort(pos+1,pos+1+n,cmp);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
if(i!=j)
flyd[i][j]=0x3f3f3f3f;
else
flyd[i][j]=0;
}
for(int i=1; i<=m; i++) {
int u,v,w;
cin>>u>>v>>w;
flyd[u][v]=min(flyd[u][v],w);
flyd[v][u]=min(flyd[v][u],w);
}
for(int k=1; k<=n; k++) {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
int u=pos[i].id,v=pos[j].id,kk=pos[k].id;
flyd[u][v]=min(flyd[u][v],flyd[u][kk]+flyd[kk][v]);
ans[u][v]=min(ans[u][v],flyd[u][v]+max(pos[i].w,max(pos[j].w,pos[k].w)));
}
}
}
while(q--) {
int u,v;
cin>>u>>v;
cout<<ans[u][v]<<endl;
}
return 0;
}