图的最短路径

Dijkstra

解决无负权图的最短路径问题。

常用模板(Dijkstra+DFS)

1. 记录所有最短路径

#include <bits/stdc++.h>
using namespace std;
const int maxn=2000;//最大顶点数
const int INF=100000;//无穷大
int n;
bool vis[maxn]={false};//vis[i]==true表示顶点i已访问
int d[maxn],G[maxn][maxn];//d记录最短距离
vector<int> pre[maxn];
void Dijkstra(int s)
{
    fill(d,d+maxn,INF);
    d[s]=0;
    for(int i=0;i<n;i++)
    {
        int u=-1,MIN=INF;
        for(int j=0;j<n;j++)
        {
            if(vis[j]==false&&d[j]<MIN)
            {
                u=j;
                MIN=d[j];
            }
        }
        if(u==-1)return;
        vis[u]=true;
        for(int v=0;v<n;v++)
        {
            if(vis[v]==false&&G[u][v]!=INF)
            {
                if(d[u]+G[u][v]<d[v])
                {
                    d[v]=d[u]+G[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }
                else if(d[u]+G[u][v]==d[v])
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}

2. 除了最短路径,还有第二个标准评次优

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000;  //最大顶点数
const int INF = 100000; //无穷大
int n;
bool vis[maxn] = {false};   //vis[i]==true表示顶点i已访问
int d[maxn], G[maxn][maxn]; //d记录最短距离
vector<int> pre[maxn];
vector<int> path, tempPath; //最优路径,临时路径
int st, optvalue;           //st路径起点,第二标准最优值
void Dijkstra(int s)
{
    fill(d, d + maxn, INF);
    d[s] = 0;
    for (int i = 0; i < n; i++)
    {
        int u = -1, MIN = INF;
        for (int j = 0; j < n; j++)
        {
            if (vis[j] == false && d[j] < MIN)
            {
                u = j;
                MIN = d[j];
            }
        }
        if (u == -1)
            return;
        vis[u] = true;
        for (int v = 0; v < n; v++)
        {
            if (vis[v] == false && G[u][v] != INF)
            {
                if (d[u] + G[u][v] < d[v])
                {
                    d[v] = d[u] + G[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }
                else if (d[u] + G[u][v] == d[v])
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}
void DFS(int v)
{
    if (v == st)
    {
        tempPath.push_back(v);
        int value;
        if (value > optvalue) //大于或小于取决于何为最优
        {
            optvalue = value;
            path = tempPath;
        }
        tempPath.pop_back();
        return;
    }
    tempPath.push_back(v);
    for (int i = 0; i < pre[v].size(); i++)
    {
        DFS(pre[v][i]);
    }
    tempPath.pop_back();
}

常见题

边权

新加cost[u][v]表示u->v的花费,增加数组c[maxn],表示从起点到u最少花费为c[u]。初始化c[s]=0,其余c[u]均为INF

for(int v=0;v<n;v++)
{
	if(vis[v]==false&&G[u][v]!=INF)
	{
		if(d[u]+G[u][v]<d[v])
		{
			d[v]=d[u]+G[u][v];
			c[v]=c[u]+cost[u][v];
		}
		else if(d[u]+G[u][v]==d[v]&&c[u]+cost[u][v]<c[v])
			c[v]=c[u]+cost[u][v];
}

点权

用weight[u]表示u点权重,并增加一个数组w[u]表示从起点s到u能收集的最大权值,初始化w[s]为weight[s],其余为0

for(int v=0;v<n;v++)
{
	if(vis[v]==false&&G[u][v]!=INF)
	{
		if(d[u]+G[u][v]<d[v])
		{
			d[v]=d[u]+G[u][v];
			w[v]=w[u]+weight[v];
		}
		else if(d[u]+G[u][v]==d[v]&&w[u]+weight[v]>w[v])
			w[v]=w[u]+weight[v];
}

最短路径条数

只增加一个数组num[ ],表示起点s到u最短路径条数为num[u],初始化num[s]为1,其余为0

for(int v=0;v<n;v++)
{
	if(vis[v]==false&&G[u][v]!=INF)
	{
		if(d[u]+G[u][v]<d[v])
		{
			d[v]=d[u]+G[u][v];
			num[v]=num[u];
		}
		else if(d[u]+G[u][v]==d[v])
			num[v]+=num[u];
}

Floyd

用来解决全源最短问题,给定的图G(V,E),求任意两点u,v之间的最短路径长度。时间复杂度O(n3),由于n3的复杂性决定了顶点数n的限制在200左右。

主要思想

如果存在顶点k,使得以k为中介点时顶点i和顶点j的当前最短距离缩短,则使用顶点k作为顶点i和顶点j的中介点,并更新dis[i][j]的最短距离。

#include<bits/stdc++.h>
using namespace std;
const int INF=10000000;
const int maxn=200;
int n,m;
int dis[maxn][maxn];

void Floyd()
{
	for(int k=0;k<n;k++)
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(dis[i][k]!=INF&&dis[k][j]!=INF&&dis[i][k]+dis[k][j]<dis[i][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
}
int main()
{
	int u,v,w;
	fill(dis[0],dis[0]+maxn*maxn,INF);
	cin>>n>>m;
	for(int i=0;i<n;i++)
		dis[i][i]=0;
	for(int i=0;i<m;i++)
	{
		cin>>u>>v>>w;
		dis[u][v]=w;
	}
	Floyd();
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
			cout<<dis[i][j];
		cout<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值