【洛谷P2966】Cow Toll Paths
题目大意:给定 N 个节点,M 条边的无向图,边有边权,点有点权,现给出 Q 个询问,每个询问查询两个节点之间的最短路径,这里最短路径的定义是两个节点之间的最短路径与这条路径中经过的节点点权的最大值之和。
题解:多源最短路问题应该用 floyd 算法来处理,由于最短路径涉及到路径中最大的点权,因此如何在决策阶段快速进行状态转移是这道题考虑的核心。若每次进行枚举点权,复杂度显然爆炸。因此在开始时对点权进行排序,这样对于带点权的最短路径的决策仅由 i,j,k 三个点点权的最大值决定,时间复杂度为 \(O(n^3)\)。
另:单纯计算多源最短路时,各个节点之间的顺序对答案无影响。(显然)
代码如下
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=251;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
ll x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
/*--------------------------------------------------------*/
int n,m,q;
int f[maxn][maxn],g[maxn][maxn],mpp[maxn];
struct node{int id,val;}ver[maxn];
bool cmp(const node &a,const node &b){return a.val<b.val;}
void read_and_parse(){
cls(f,0x3f),cls(g,0x3f);
for(int i=1;i<=n;i++)f[i][i];
n=read(),m=read(),q=read();
for(int i=1;i<=n;i++)ver[i].id=i,ver[i].val=read();
sort(ver+1,ver+n+1,cmp);
for(int i=1;i<=n;i++)mpp[ver[i].id]=i;
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
f[mpp[x]][mpp[y]]=f[mpp[y]][mpp[x]]=min(z,f[mpp[y]][mpp[x]]);
}
}
void floyd(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
g[i][j]=min(g[i][j],f[i][j]+max(max(ver[i].val,ver[j].val),ver[k].val));
}
}
void solve(){
floyd();
while(q--){
int s=mpp[read()],t=mpp[read()];
printf("%d\n",g[s][t]);
}
}
int main(){
read_and_parse();
solve();
return 0;
}