题解 P2966 【[USACO09DEC]牛收费路径Cow Toll Paths】
居然发现没有人写dijkstra的算法过这个题
那我这个水过的蒟蒻就来讲讲dijkstra怎么做
如果不会dijkstra 请先进这个题进行学习qwq
这个思路比较清奇
首先 我们这个题目中有个坑点 就是说 每一次要加上走过路径之中点权最大的点
其实很好想的就是每一次处理的时候存一下最大点权 然后就发现 不是TLE即MLE
然后 我们就有了这个思路:
1 一重循环k 表示当前我们这条路上的最大点权 即所有可经过点的点权≤点k的权值
2 在循环k里面做dijkstra 注意经过的点只能是点权≤k点的 不然就错了
3 在更新完dist后 计算答案 计算式要加上k点的点权
这样一分析 时间复杂度Θ(卡过
最后来上一发代码(要抄也得先理解思路)
//这里写一笔 我的标程没有写链式前向星 用的是邻接矩阵
#include<bits/stdc++.h>
using namespace std;
// n,m,query 就是n,m,k
// p代表点的权值 maze是邻接矩阵 dist是处理出来的某个点到所有点的最小值(dijkstra) vis标记 ans不必多说 储存答案
int n,m,query;
int p[260],maze[260][260],dist[260],ans[260][260],vis[260];
void dijkstra(int k){
//当然 数组不清空 交题见祖宗
memset(vis,0,sizeof(vis));
memset(dist,0x3f,sizeof(dist));
//以下是disjktra正常操作
dist[k]=0;
for(int i=1;i<=n;i++){
int v=-1;
/*看到这里你可能会奇怪 (p[u]<=p[k]) 什么鬼
其实很好理解的 我把我每一次做dijkstra的点拉出来 做为当前的最大点权 那当然不可以进入比最大点权权值还要大的点了 */
for(int u=1;u<=n;u++) if(((dist[u]<dist[v])||(v==-1))&&(p[u]<=p[k])&&(!vis[u])) v=u;
if(v==-1) break;
vis[v]=true;
//其实这里(p[u]>p[k])跟上面那个一样的 然后就dijkstra正常走一波
for(int u=1;u<=n;u++){
if(p[u]>p[k]) continue;
dist[u]=min(dist[u],dist[v]+maze[v][u]);
}
}
}
int main(){
//清空赋值读入 这里就不多讲了
memset(ans,0x3f,sizeof(ans));
memset(maze,0x3f,sizeof(maze));
cin>>n>>m>>query;
for(int i=1;i<=n;i++) cin>>p[i];
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
maze[a][b]=maze[b][a]=min(maze[a][b],c);
}
//这里的k代表的是当前我选中的点 这个点代表了当前的最大点权 即在本次我dijkstra中选出可用的点的点权不可以有大于它的
for(int k=1;k<=n;k++){
dijkstra(k);//进函数
//下面是计算ans 这里计算ans是由选出的最大点权的点到任意两个点的距离 别忘了加上最大点权
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ans[i][j]=min(ans[i][j],dist[i]+dist[j]+p[k]);
}
//对于每一次询问 我们处理出它的答案:)
for(int i=1;i<=query;i++){
int a,b;
cin>>a>>b;
cout<<ans[a][b]<<endl;
}
return 0;
}