最短路
单源最短路
Dijkstra(只能解决正权边,单源)
它的逻辑可以理解为走当前最近可到达的且无法确定它是不是最短路的一个点,找它的最短路
读入所有的边和边权,再把所有点到起点的距离变为无穷大,自己变为0
点击查看代码
int n,m,s,t;
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
g[u][v]=w;
g[v][u]=w;
}
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
//接下来就是不断更新更短距离,更新结束后dis存的就是每个点到起点的最短距离
for(int i=1;i<=n;i++){
int tt=-1;
for(int j=1;j<=n;j++){
if(vis[j]==0){
if(tt==-1)
tt=j;
else{
if(dis[tt]>dis[j])
tt=j;
}
}
}
vis[tt]=1;
for(int j=1;j<=n;j++){
if(g[tt][j]>0) {
dis[j] = min(dis[j], dis[tt] + g[tt][j]);
}
//cout<<j<<" "<<dis[j]<<endl;
}
}
这个做法是在用邻接矩阵,当n=1e5时一定会爆,那就加一个堆优化,并且用vector存图
点击查看代码
#define PII pair<int,int>
int dis[100010];
vector<PII>g[100010];
int vis[100010];
void dij(int s){
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,s});
while(!q.empty()){
auto [xx,e]=q.top();
q.pop();
if(vis[e]){
continue;
}
vis[e]=1;
for(auto [u,v]:g[e]){
if(dis[u]>dis[e]+v){
dis[u]=dis[e]+v;
q.push({dis[u],u});
}
}
}
}
void solve() {
int n,m,s;
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
g[a].push_back({b,c});
}
dij(s);
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return ;
}
第一处优化就是用vector套pair存储图,然后在搜索的时候使用堆优化,把dis数组放在第一维排序,找到的第一个就是当前最短边,后边就和之前的查找一样。
多源最短路
Floyd
这个最短路其实就是dp的思想了,不断更新i,j之间的最短距离
点击查看代码
int g[110][110];
void solve() {
int n,m;
cin>>n>>m;
memset(g,0x3f,sizeof(g));
for(int i=1;i<=n;i++){
g[i][i]=0;
}
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
g[b][a]=min(g[b][a],c);
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<g[i][j]<<" ";
}
cout<<endl;
}
return ;
}