最短路径(迪杰斯特拉 题目 代码 C++ 注解)

文章详细描述了五个问题,涉及使用迪杰斯特拉算法解决哈利波特考试的连通性问题,旅游规划中寻找最短路径和最少花费,城市间紧急救援的路径规划,天梯地图的最短时间和距离计算,以及战略游戏中通过优先队列找到攻击路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

题目一(哈利.波特的考试): 

​代码: 

题目二(旅游规划):

代码:

题目三(城市间的紧急救援):

代码:

题目四(天梯地图):

代码:

题目五(直捣黄龙):

代码:


题目一(哈利.波特的考试): 

 代码: 

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
    int v,w;
    bool operator <(const node&y) const
    {return w>y.w;}
};
vector<node> e[110];
int dis[110],vis[110];
void dij(int t)
{
    priority_queue<node> q;
    dis[t]=0;
    q.push({t,dis[t]});
    while(q.size())
    {
        int u=q.top().v;
        q.pop();
        if(vis[u])
            continue;
        vis[u]=1;
        for(auto i:e[u])
        {
            int v=i.v,w=i.w;
            if(vis[v]==0)
            {
                if(dis[v]>dis[u]+w)
                {
                    dis[v]=dis[u]+w;
                    q.push({v,dis[v]});
                }
            }
        }
    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    while(m--)
    {
        int v1,v2,w;
        cin>>v1>>v2>>w;
        e[v1].push_back({v2,w});
        e[v2].push_back({v1,w});
    }
    int flag,minn=1e9;//flag标记编号,minn存魔咒最短的值
    int s=0;//记录无法连通的个数
    for(int i=1;i<=n;i++)//从每个点开始做dij
    {
        memset(dis,0x3f3f3f3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dij(i);//迪杰斯特拉
        int maxx=0;//记录该点出发到其它点的最长距离
        for(int i=1;i<=n;i++)
        {
            if(dis[i]>maxx)
            {
                maxx=dis[i];
            }
        }
        int cnt=0;//标记是否有没访问到的
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                cnt=1;
                break;
            }
        }    
        if(maxx<minn && cnt==0)//最长的魔咒比之前的短且没有不访问的点,则更新
        {
            flag=i,minn=maxx;
        }
        if(cnt==1)//有没访问的,s加一
            s++;
    }
    if(s==n)//无法只带一只动物
        cout<<0;
    else
        cout<<flag<<" "<<minn;
}

题目二(旅游规划):

代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
    int v, w, z;
    bool operator <(const node& y)const
    {
        return w < y.w;
    }
};
priority_queue<node> q;
vector<node> e[10100];
int dis[1000], vis[1000], val[1000];
void dij(int t)
{
    memset(dis, 0x3f3f3f, sizeof(dis));
    dis[t] = 0;
    val[t] = 0;
    q.push({ t,dis[t] });
    while (q.size())
    {
        int u = q.top().v;
        q.pop();
        if (vis[u])
            continue;
        for (auto i : e[u])
        {
            int v = i.v, w = i.w, z = i.z;
            if (vis[v] == 0)
            {
                if (dis[v] > dis[u] + w)//距离更短,更新
                {
                    dis[v] = dis[u] + w;//更新距离
                    val[v] = val[u] + z;//更新花费
                    q.push({v,dis[v]});
                }
                if (dis[v] == dis[u] + w && val[v] > val[u] + z)//距离相等,花费更小,更新
                {
                    val[v] = val[u] + z;
                }
            }
        }
    }
}
int main()
{
    int n, m, s, d;
    cin >> n >> m >> s >> d;
    while (m--)
    {
        int x1, x2, v, w;
        cin >> x1 >> x2 >> v >> w;
        e[x1].push_back({ x2,v,w });//无向图,建图
        e[x2].push_back({ x1,v,w });
    }
    dij(s);
    cout << dis[d] << " " << val[d] << endl;
}

题目三(城市间的紧急救援):

代码:

#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
struct node
{
	int v, w;
	bool operator <(const node& y) const
	{
		return w > y.w;
	}
};
priority_queue<node> q;
vector<node> e[101000];
int dis[1010], vis[1010], path[1010], jiu[1010], path_count[1010], val[1010];
void dij(int t)
{
	memset(dis, 0x3f3f3f, sizeof(dis));
	jiu[t] = val[t];//初始救援人数等于起点救援人数
	dis[t] = 0;
	path[t] = t;//初始前驱为自身
	path_count[t] = 1;//初始路径数量为1
	q.push({ t,dis[t] });
	while (q.size())
	{
		int u = q.top().v;
		q.pop();
		if (vis[u])//访问过
			continue;
		vis[u] = 1;
		for (auto i : e[u])
		{
			int v = i.v, w = i.w;
			if (vis[v] == 0)//没访问过
			{
				if (dis[v] > dis[u] + w)//距离更短
				{
					jiu[v] = jiu[u] + val[v];//救援数等于前驱的加上自身的
					dis[v] = dis[u] + w;
					path[v] = u;//记录前驱
					path_count[v] = path_count[u];//路径数为前驱路径数
					q.push({ v,dis[v] });
				}
				else if (dis[v]==dis[u]+w)//距离相等
				{
					path_count[v] += path_count[u];//路径数自身加上前驱的
					if (jiu[v] < val[v] + jiu[u])//救援人员更多,则更新
					{
						jiu[v] = val[v] + jiu[u];
						path[v] = u;
					}
				}
			}
		}
	}
}
int main()
{
	int n, m, s, d;
	cin >> n >> m >> s >> d;
	for (int i = 0; i < n; i++)//救援队数
		cin >> val[i];
	for (int j = 0; j < m; j++)//无向图,建边
	{
		int v1, v2, w;
		cin >> v1 >> v2 >> w;
		e[v1].push_back({ v2,w });
		e[v2].push_back({ v1,w });
	}
	dij(s);
	cout << path_count[d] << " ";
	cout << jiu[d] << endl;
	int a[1010];
	int k = 0;
	while (d != s)//存路径
	{
		a[k] = d;
		d = path[d];
		k++;
	}
	cout << s << " ";
	for (int i = k - 1; i >= 0; i--)//反向输出路径
	{
		if (i != k - 1)
			cout << " ";
		cout << a[i];
	}
}

题目四(天梯地图):

 

 

代码:

#include<iostream>//最后一个测试点没过
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
    int v, w,z;
    bool operator <(const node& y) const
    {
        return w > y.w;
    }
};
vector<node> e[1010];
int dist[1010], disd[1010], vis[1010];
string pathd[1010] = { "" }, patht[1010] = { "" };//分别记录最短距离,最短时间
void dijd(int t, int dis[], string path[])//求最短路径
{
    memset(vis, 0, sizeof(vis));
    priority_queue<node> q;
    int cnt[1010]={0};//记录访问城市个数
    memset(cnt, 0, sizeof(cnt));
    cnt[t]=1;//初始访问一个
    dis[t] = 0;
    char c = t + '0';//int类型转为char
    path[t] += c;//自身前驱记录为自身
    q.push({ t,dis[t] });
    while (q.size())
    {
        int u = q.top().v;
        q.pop();
        if (vis[u])//访问过
            continue;
        vis[u] = 1;
        for (auto i : e[u])
        {
            int v = i.v, w = i.w;
            if (vis[v] == 0)//没访问过
            {
                char c = v + '0';//int传为char
                if (dis[v] > dis[u] + w)//距离更短,更新
                {
                    dis[v] = dis[u] + w;//更新距离
                    path[v]="";
                    path[v] = path[u] + c;//路径为前驱加上自身
                    cnt[v]=cnt[u]+1;//访问城市数量等于前驱数量加自身
                    q.push({ v,dis[v] });//入队
                }
                else  if (dis[v] == dis[u] + w && cnt[v] > cnt[u] + 1)//距离一样,访问城市更少,更新
                {
                    cnt[v]=cnt[u]+1;//访问城市数量等于前驱数量加自身
                    path[v]="";
                    path[v] = path[u] + c;//路径为前驱加上自身
                }
            }
        }
    }
}
void dijt(int t, int dis[], string path[])//求最短时间
{
    memset(vis, 0, sizeof(vis));
    priority_queue<node> q;
    int cnt[1010];//记录到该点的距离
    memset(cnt, 0, sizeof(cnt));
    cnt[t] = 0;//初始点距离为0
    dis[t] = 0;
    char c = t + '0';
    path[t] += c;//初始前驱为自身
    q.push({ t,dis[t] });
    while (q.size())
    {
        int u = q.top().v;
        q.pop();
        if (vis[u])//访问过
            continue;
        vis[u] = 1;
        for (auto i : e[u])
        {
            int v = i.v, z = i.z, w=i.w;
            if (vis[v] == 0)
            {
                char c = v + '0';//int转char
                if (dis[v] > dis[u] + z)//时间更短,更新
                {
                    dis[v] = dis[u] + z;//更新时间
                    cnt[v] = cnt[u] + w;//更新距离
                    path[v]="";
                    path[v] = path[u] + c;//路径为前驱加上自身
                    q.push({ v,dis[v] });
                }
                else  if (dis[v] == dis[u] + z && cnt[u]+w<cnt[v])//时间相等,距离更短,更新
                {
                    cnt[v] = cnt[u]+w;//更新距离
                    path[v]="";
                    path[v] = path[u] + c;//路径为前驱加上自身
                }
            }
        }
    }

}
int main()
{
    int n, m;
    cin >> n >> m;
    while (m--)
    {
        int v1, v2, o, l, t;
        cin >> v1 >> v2 >> o >> l >> t;
        if (o == 1)
        {
            e[v1].push_back({ v2,l,t });
        }
        else
        {
            e[v1].push_back({ v2,l,t });
            e[v2].push_back({ v1,l ,t});
        }
    }
    int s, d;
    cin >> s >> d;
    memset(dist, 0x3f3f3f3f, sizeof(dist));
    memset(disd, 0x3f3f3f3f, sizeof(disd));
    dijt(s, dist, patht);
    dijd(s, disd, pathd);
    if (pathd[d] != patht[d])//路径 不相同 分别输出
    {
        cout << "Time = " << dist[d] << ": ";
        for (int j = 0; j < patht[d].size(); j++)
        {
            if (j != 0)
                cout << " => ";
            cout << patht[d][j];
        }
        cout << endl;
        cout << "Distance = " << disd[d] << ": ";
        for (int j = 0; j < pathd[d].size(); j++)
        {
            if (j != 0)
                cout << " => ";
            cout << pathd[d][j];
        }
    }
    else//路径相同
    {
        cout << "Time = " << dist[d] << "; " << "Distance = " << disd[d] << ": ";
        for (int j = 0; j < pathd[d].size(); j++)
        {
            if (j != 0)
                cout << " => ";
            cout << pathd[d][j];
        }

    }

}

题目五(直捣黄龙):

 

代码:

#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<queue>
using namespace std;
struct node
{
	int v;
	int w;
	bool operator <(const node& y)const
	{
		return w > y.w;
	}
};
map<string, int> v;//通过城市名访问敌军数
map<int, string> names;//通过编号访问城市名
map<string, int>id;//通过城市名访问编号
vector<node> e[1010];//存边
int dis[1010], vis[1010], path[1010], shu[1010], dr[1010];//vis访问数组,path存路径,shu存路径数量,dr存敌人数量
priority_queue<node> q;
void dij(int t)
{
	memset(dis, 0x3f3f3f3f, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	int cnt[1010];//经过城市的个数
	memset(cnt, 0, sizeof(vis));
	shu[t] = 1;//初始路径为1
	cnt[t] = 1;//初始经过城市1
	dr[t] = 0;//初始敌人为0
	path[t] = t;//初始前驱为自身
	dis[t] = 0;
	q.push({ t,dis[t] });
	while (q.size())
	{
		int u = q.top().v;//取边最小的点
		q.pop();
		if (vis[u])//访问过,跳过
			continue;
        vis[u]=1;
		for (auto i : e[u])//访问相连边
		{
			int v1 = i.v, w = i.w;//取相连点和权值
			if (vis[v1] == 0)
			{
				if (dis[v1] > dis[u] + w)//长度更短,更新
				{
					shu[v1] = shu[u];//到该点的路径数继承前驱的路径数
					path[v1] = u;//保存前驱
					dis[v1] = dis[u] + w;//更新最短长度
					cnt[v1]=cnt[u]+1;//经过的城市为前驱+自身
					dr[v1] = dr[u] + v[names[v1]];//敌人数量为前驱加自身城市的敌人数量
                    q.push({ v1,dis[v1] });//入队
				}
				else if (dis[v1] == dis[u] + w)//长度相同
				{
					shu[v1] += shu[u];//路径数自身原本的加上该前驱的路径数
					if (cnt[v1] < cnt[u] + 1)//访问城市比之前多,更新
					{
						cnt[v1] = cnt[u] + 1;//更新访问数量
						path[v1] = u;//更新前驱
						dr[v1] = dr[u] + v[names[v1]];//更新敌人数量
					}
					else if (cnt[v1] == cnt[u] + 1 && dr[v1] < dr[u] + v[names[v1]])//路径相同,访问城市数量相同,敌人更大,更新
					{
						path[v1] = u;//更新前驱
						dr[v1] = dr[u] + v[names[v1]];//更新敌人数
					}
				}
			}
		}
	}
}
int main()
{
	int n, k;
	string s, d;
	cin >> n >> k >> s >> d;
	v[s] = 0;//大本营,敌人数量为0
	names[1] = s;//大本营编号为1
	id[s] = 1;//大本营编号为1
	for (int i = 2; i <= n; i++)
	{
		string name;
		int num;
		cin >> name >> num;
		v[name] = num;//通过名字访问敌军数量
		names[i] = name;//通过编号访问名字
		id[name] = i;//通过名字访问编号
	}
	while (k--)
	{
		string s1, s2;
		int w;
		cin >> s1 >> s2 >> w;
		int a = id[s1];
		int b = id[s2];
		e[a].push_back({ b,w });//建立边,无向图
		e[b].push_back({ a,w });
	}
	dij(id[s]);
	//for (int i = 1; i <= n; i++)
		//cout << dis[i] << " ";
	int t = id[d];
	string a[1010];
	k = 0;
	while (path[t] != t)//保存节点
	{
		a[k++] = names[t];
		//cout<<names[t]<<" ";
		t = path[t];
	}
	a[k] = s;
	for (int i = k; i >= 0; i--)//倒序输出
	{
		if (i != k)
			cout << "->";
		cout << a[i];
	}
	cout << endl;
	cout << shu[id[d]] << " " << dis[id[d]] << " " << dr[id[d]];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值