迪杰斯特拉算法的具体应用

fill与memset的区别介绍

例一

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=500;
const int INF=1000000000;
bool isin[maxn]={false};
int G[maxn][maxn];
int path[maxn],rescue[maxn],num[maxn];
int weight[maxn];
int citynum,roadnum,begins,e;

void Dijisktra(int a){
    fill(path,path+maxn,INF);//记录最短距离
    memset(rescue,0,sizeof(rescue));//记录点权
    memset(num,0,sizeof(num));//记录最短路径的条数
    path[a]=0;
    rescue[a]=weight[a];
    num[a]=1;
    for(int i=0;i<citynum;i++){
        int pi=-1,pv=INF;
        for(int j=0;j<citynum;j++){
            //找最短距离的结点
            if(isin[j]==false&&path[j]<pv){
                pi=j;
                pv=path[j];
            }
     }
        if(pi==-1) return;
        isin[pi]=true;
        for(int k=0;k<citynum;k++){
            if(isin[k]==false&&G[pi][k]!=INF)
            {
                if(G[pi][k]+path[pi]<path[k])
                {
                    path[k]=G[pi][k]+path[pi];
                    num[k]=num[pi];//更新最短路径数:不相同就覆盖
                    rescue[k]=rescue[pi]+weight[k];
                }else 
                if(G[pi][k]+path[pi]==path[k]){
                    if(rescue[pi]+weight[k]>rescue[k])
                    rescue[k]=rescue[pi]+weight[k];//存大值
                    num[k]+=num[pi];//最短路径条数之和:相同累加
                }
            }
        }
    }
}
int main(){
    int v1,v2;//顶点及边权-距离
    fill(G[0],G[0]+maxn*maxn,INF);
    cin>>citynum>>roadnum>>begins>>e;
    for(int i=0;i<citynum;i++){
        cin>>weight[i];//记录点权-救援小组数目
    }
    for(int j=0;j<roadnum;j++){
        cin>>v1>>v2>>G[v1][v2];
        //建立无向图
        G[v2][v1]=G[v1][v2];
    }
    Dijisktra(begins);
    cout<<num[e]<<" "<<rescue[e];
    return 0;
}

例二


cpp 复制代码
#include <iostream>
using namespace std;
const int maxn=100;
const int INF=1000000000;
bool isin[maxn]={false};
int G[maxn][maxn],expense[maxn][maxn];
int path[maxn],cost[maxn],pre[maxn];
int citynum,roadnum,b,e;

void Dijisktra(int a){//求最短路径
    fill(path,path+maxn,INF);
    fill(cost,cost+maxn,INF);
    path[a]=0;
    cost[a]=0;
    for(int i=0;i<citynum;i++) pre[i]=i;
    for(int i=0;i<citynum;i++){
        int m=-1,mv=INF;
        for(int j=0;j<citynum;j++){
            if(isin[j]==false&&path[j]<mv){
                m=j;
                mv=path[j];
            }
        }
        if(m==-1) return;
        isin[m]=true;
        for(int k=0;k<citynum;k++){
            if(isin[k]==false&&G[m][k]!=INF)
            {
                if(G[m][k]+path[m]<path[k]){
                    path[k]=G[m][k]+path[m];
                    cost[k]=expense[m][k]+cost[m];
                    pre[k]=m;
                }else if(G[m][k]+path[m]==path[k]){
                    if(cost[k]>expense[m][k]+cost[m])
                    cost[k]=expense[m][k]+cost[m];
                    pre[k]=m;
                }
            }
        }
    }
}
void DFSprint(int now){//打印
    if(now==b){
        cout<<now<<" ";
        return;
    }
    DFSprint(pre[now]);
    cout<<now<<" ";
}
int main(){
    int v1,v2;
    fill(G[0],G[0]+maxn*maxn,INF);
    fill(expense[0],expense[0]+maxn*maxn,INF);
    cin>>citynum>>roadnum>>b>>e;
    for(int i=0;i<roadnum;i++){
        cin>>v1>>v2>>G[v1][v2]>>expense[v1][v2];
        G[v2][v1]=G[v1][v2];
        expense[v2][v1]=expense[v1][v2];
    }
    Dijisktra(b);
    DFSprint(e);
    cout<<path[e]<<" "<<cost[e]<<endl;
    return 0;
}

拓展

用迪杰斯特拉+DFS求最短路径的方法

关键代码:

cpp 复制代码
const int maxn=100;
const int INF=10000000000;
bool isin[maxn]={false};
int G[maxn][maxn],num;
int path[maxn],w[maxn];
vector<int> pre[maxn];//记录最短路径的前驱:考虑会有多个
vector<int> minPath,temPath;//只记录最优或当前路径

void Dijisktra(int a){
    fill(path,path+maxn,INF);
    path[a]=0;
    for(int i=0;i<num;i++){
        int m=-1,mv=INF;
        for(int j=0;j<num;j++){
            if(isin[j]==false&&path[j]<mv){
                m=j;
                mv=path[j];
            }
        }
        if(m==-1) return;
        isin[m]=true;
        for(int k=0;k<num;k++){
            if(isin[k]==false&&G[m][k]!=INF)
            {
                if(G[m][k]+path[m]<path[k]){
                    path[k]=G[m][k]+path[m];
                    //找到更优路径,清空,装最短的
                    pre[k].clear();
    //m结点加入k结点的前驱列表中,即为pre[k][i]==m;
                    pre[k].push_back(m);
                }else if(G[m][k]+path[m]==path[k]){
//此时有多条最短路径,即存在多个前驱结点,直接加入即可
                    pre[k].push_back(m);
                }
            }
        }
    }
}

void DFSprint(int now,int begins){
    int optValue=0;
    if(now==begins){
        temPath.push_back(begins);
        if(value>optValue){//更新最优
            optValue=value;
            minPath=temPath;
        }
        temPath.pop_back();//弹出第一个
        return;
    }
    temPath.push_back(now);
    for(int i=0;i<pre[now].size();i++){
        //遍历当前结点的前驱结点
        DFSprint(pre[now][i]);//不断递归now结点的前驱列表
    }
    temPath.pop_back();//依次弹出第二个.....
}
//计算边权和
int edge=0;
for(int i=temPath.size()-1;i>0;i--){
    int now=temPath[i],next=temPath[i-1];
    edge+=G[now][next];//计算边权
}
//计算点权和
int weight=0;
for(int i=temPath.size()-1;i>0;i--){
    int now=temPath[i];//当前结点下标
    weight+=w[now];
}

例二:Dijiskatra+DFS

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
const int maxn=100;
const int INF=100000000;
bool isin[maxn]={false};
int G[maxn][maxn],expense[maxn][maxn];
int path[maxn],minValue=INF;
vector<int> pre[maxn],temPath,minPath;
int citynum,roadnum,b,e;

void Dijisktra(int a){
    fill(path,path+maxn,INF);
    path[a]=0;
    for(int i=0;i<citynum;i++){
        int m=-1,mv=INF;
        for(int j=0;j<citynum;j++){
            if(isin[j]==false&&path[j]<mv){
                m=j;
                mv=path[j];
            }
        }
        if(m==-1) return;
        isin[m]=true;
        for(int k=0;k<citynum;k++){
            if(isin[k]==false&&G[m][k]!=INF){
                if(path[m]+G[m][k]<path[k]){
                    path[k]=path[m]+G[m][k];
                    pre[k].clear();
                    pre[k].push_back(m);
                }else if(path[m]+G[m][k]==path[k]){
                    pre[k].push_back(m);
                }
            }
        }
    }
}
void DFSprint(int now){
    int tempValue=0;
    if(now==b){
        temPath.push_back(now);
        for(int i=temPath.size()-1;i>0;i--){
            int v1=temPath[i],v2=temPath[i-1];
            tempValue+=expense[v1][v2];
        }
        if(tempValue<minValue){
            minValue=tempValue;
            minPath=temPath;
        }
        temPath.pop_back();//出队
    }
    temPath.push_back(now);
    for(int i=0;i<pre[now].size();i++){
        DFSprint(pre[now][i]);
    }
    temPath.pop_back();
}
int main(){
    int v1,v2;
    fill(G[0],G[0]+maxn*maxn,INF);
    fill(expense[0],expense[0]+maxn*maxn,INF);
    cin>>citynum>>roadnum>>b>>e;
    for(int i=0;i<roadnum;i++){
        cin>>v1>>v2>>G[v1][v2]>>expense[v1][v2];
        G[v2][v1]=G[v1][v2];
        expense[v2][v1]=expense[v1][v2];
    }
    Dijisktra(b);
    DFSprint(e);
    for(int i=minPath.size()-1;i>=0;i--)
    cout<<minPath[i]<<" ";
    cout<<path[e]<<" "<<minValue<<endl;
    return 0;
}