(*****dijkstra升级版)直捣黄龙(紧急救援加强版)

本文探讨了Dijkstra算法的两种实现方式,包括常规的算法实现及其复杂性,以及利用优先队列来优化思路,提高了算法的效率。
摘要由CSDN通过智能技术生成

 

代码一、常规算法,比较麻烦

//使用map容器将字符串和数字建立关系
//dijkstra算法保存路径
#include<iostream>
#include<vector>
#include<map>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 210;
map<string,int>mp;
int n,k,w;
struct edge
{
    int to,cost;
};
vector<edge> G[N];
int num[N];   //每个城镇敌军数量
int dis[N];  //最短距离
int cnt[N];  //解放城镇数量
int sumnum[N];   //能杀伤多少敌军
int pred[N];    //记录上一个节点序号
int cntshort[N];   //到某个顶点的最短路条数
int book[N];   //记录是否访问过
vector<int>ljd;
int s,des;
void dijkstra()
{
    for(int i=0;i<n;i++)
        dis[i]=INF;
    dis[s]=0;
    cntshort[s]=1;    //到某个顶点的最短路条数
    book[s]=1;
    for(int i=0;i<G[s].size();i++)  //对起点的邻接点进行初始化
    {
        int next=G[s][i].to;
        dis[next]=G[s][i].cost;   //距离
        cntshort[next]=1;  //最短路径条数
        sumnum[next]=num[next];   //杀敌数量
        pred[next]=s;    //前一个节点
    }
    int Min,Minnum;
    for(int i=1;i<n;i++)
    {
        Min=INF+1;
        Minnum=-1;
        for(int j=1;j<n;j++)
        {
            if(dis[j]<Min&&book[j]!=1)
            {
                Min=dis[j];
                Minnum=j;
            }
        }
        book[Minnum]=1;
        for(int j=0;j<G[Minnum].size();j++)
        {
            edge& e=G[Minnum][j];
            int d2=dis[Minnum]+e.cost;   //待更新的距离
            if(dis[e.to]>d2)
            {
                dis[e.to]=d2;
                pred[e.to]=Minnum;
                cnt[e.to]=cnt[Minnum]+1;   //解放城市数量加1
                sumnum[e.to]=sumnum[Minnum]+num[e.to];   //杀死军队数量
                cntshort[e.to]=cntshort[Minnum];   //最短路条数
            }
            else if(dis[e.to]==d2)
            {
                cntshort[e.to]+=cntshort[Minnum];   //最短路径条数
                //解放城市
                if(cnt[e.to]<cnt[Minnum]+1)
                {
                    pred[e.to]=Minnum;
                    cnt[e.to]=cnt[Minnum]+1;
                    sumnum[e.to]=sumnum[Minnum]+num[e.to];
                }
                else if(cnt[e.to]==cnt[Minnum]+1)
                {
                    //消灭的敌数
                    if(sumnum[e.to]<sumnum[Minnum]+num[e.to])
                    {
                        sumnum[e.to]=sumnum[Minnum]+num[e.to];
                        pred[e.to]=Minnum;
                    }
                }
            }
        }
    }
}
void dfs(int *p,int x,vector<int>& a)
{
    if(x==s)
    {
        a.push_back(x);
        return ;
    }
    dfs(p,p[x],a);
    a.push_back(x);
}
int main()
{
    string city[N];   //表示字符串,对应mp表示字符串对应的数字
    string city1,city2;
    cin>>n>>k>>city1>>city2;
    city[0]=city1;
    mp[city1]=0;
    for(int i=1;i<n;i++)
    {
        cin>>city[i]>>w;
        mp[city[i]]=i;   //建立映射,便于查找
        num[i]=w;      //存储军队的个数
    }

    s=0;   //开始城市的序号
    des=mp[city2];     //目标城市序号
    string a,b;
    int w;
    int u,v;
    for(int i=0;i<k;i++)
    {
        cin>>a>>b>>w;
        u=mp[a];
        v=mp[b];
        G[u].push_back({v,w});  //存储信息,相当于双向边
        G[v].push_back({u,w});
    }
    dijkstra();
    dfs(pred,des,ljd);   //前一个节点 ,目标点,最短路径
    //输出最合适的进攻路径
    cout<<city[0];
    for(int i=1;i<ljd.size();i++)
        cout<<"->"<<city[ljd[i]];
    //输出最快进攻路径的条数,最短进攻距离,歼敌总数
    printf("\n%d %d %d",cntshort[des],dis[des],sumnum[des]);
    return 0;
}

代码二、使用优先队列,思路更清晰

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 205;
int n,k,t,val[N],dis[N],cnt[N],num[N],lib[N];
int pre[N];
bool vis[N],flag;
vector<PII> mar[N];
string s,d,str,ptr;
unordered_map<string,int> m1;
unordered_map<int,string> m2;
void Print(int x){
    if(x == 0)  return;
    Print(pre[x]);
    if(flag)    cout << "->";
    else    flag = 1;
    cout << m2[x];
}
void Dijkstra(int s) {
    memset(dis,0x3f,sizeof(dis));
    priority_queue<PII,vector<PII>,greater<PII>> qu;
    qu.push({0,s});
    cnt[s] = 1,dis[s] = 0;
    while(!qu.empty()) {
        int u = qu.top().y;
        qu.pop();
        if(vis[u])  continue;
        vis[u] = 1;
        for(int i = 0; i < mar[u].size(); ++i) {
            int v = mar[u][i].x,w = mar[u][i].y;
            if(dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                cnt[v] = cnt[u];
                lib[v] = lib[u] + 1;
                num[v] = num[u] + val[v];
                pre[v] = u;
                qu.push({dis[v],v});
            } else if(dis[v] == dis[u] + w) {
                cnt[v] += cnt[u];
                if(lib[v] < lib[u] + 1) {
                    lib[v] = lib[u] + 1;
                    num[v] = num[u] + val[v];
                    pre[v] = u;
                } else if(lib[v] == lib[u] + 1 && num[v] < num[u] + val[v]) {
                    num[v] = num[u] + val[v];
                    pre[v] = u;
                }
                qu.push({dis[v],v});
            }
        }
    }
    int p = m1[d];
    Print(p);
    cout << endl;
    cout << cnt[p] << " " << dis[p] << " " << num[p] << endl;
}
int main() {
    cin >> n >> k >> s >> d;
    m1[s] = 1,m2[1] = s;
    for(int i = 2; i <= n; ++i) {
        cin >> str >> t;
        m1[str] = i;
        m2[i] = str;
        val[i] = t;
    }
    for(int i = 0; i < k; ++i) {
        cin >> str >> ptr >> t;
        int a = m1[str],b = m1[ptr];
        mar[a].push_back({b,t});
        mar[b].push_back({a,t});
    }
    Dijkstra(1);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值