(实时更新)蓝桥杯知识点笔记 | (九)图论

文章介绍了图论中的最短路问题,包括使用Dijkstra算法和Floyd算法求解。通过示例代码展示了如何在不同场景下寻找两点间的最短路径,并提供了多个题目链接供读者实践。
摘要由CSDN通过智能技术生成

小标题的超链接为原题链接,点击跳转

8. 图论

最短路问题(shortest-path problem)是图论中的经典问题之一,可用来解决管路铺设、线路安装、厂区布局和设备更新等实际问题。

基本内容是:假设网络中的每条边都有一个 权重(常用长度、成本、时间等表示),最短路问题的目标是找出 给定两点(通常是源节点和汇节点)之间总权重之和最小的路径。

8.1 遍历

acwing845树的重心

题目

image-20230329205134893

代码

 // 树的重心
#include <iostream>
#include <cstring>
using namespace std;

const int N = 1E5+10, M = N*2;

int h[N], e[M], ne[M], idx;
bool st[N];
int n;
int ans = N;

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
	return;
}

int dfs(int u)
{
	st[u] = true;

	int sum = 1, res = 0; // 以u为根节点,sum保留所有子树+根节点的重量和,res保留u作为重心时的最大点数和
	for(int i=h[u]; i!=-1; i=ne[i])
	{
		int j = e[i];
		if(!st[j])
		{
			int s = dfs(j);
			sum += s;
			res = max(res, s);
		}
	}
	res = max(res, n-sum);

	ans = min(ans, res);
	return sum;
}

int main()
{
	memset(h, -1, sizeof h);
	cin >> n;
	for(int i=1; i<=n-1; i++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b), add(b, a);
	}
	dfs(1);
	cout << ans;
}

8.2 dijkstra求最短路

路径

题目

image-20230404191930065

代码

// 路径
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 2100;
int g[N][N];
int st[N];
int dist[N];

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);

    dist[1] = 0;

    for(int i=1; i<=2021; i++)
    {
        // 找到不在st数组里的最小的点
        int res = -1;
        for(int j=1; j<=2021; j++)
            if(!st[j] && (res==-1 || dist[j] < dist[res])) res = j;
        
        // 标记
        st[res] = 1;

        // 更新所有点
        for(int j=1; j<=2021; j++)
            dist[j] = min(dist[j], dist[res] + g[res][j]);
    }
    if(dist[2021] == 0x3f3f3f3f) return -1;
    else return dist[2021];
}

int main()
{
    // 请在此输入您的代码
    memset(g, 0x3f, sizeof g);
    for(int i=1; i<=2021; i++)
        for(int j=1; j<=2021; j++) if(i != j)
        {
            int a = i, b = j;
            if(abs(a-b) <= 21) g[a][b] = a*b/__gcd(a, b);
        }

    int t = dijkstra();

    cout << t;
    return 0;
}
出差

题目

image-20230405211756980

代码

// 出差
#include<iostream>
#include<cstring>
using namespace std;

const int N = 1010;
int g[N][N];
int dist[N];
bool st[N];
int wait[N];
int n, m;

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);

    dist[1] = 0;

    for(int i=1; i<=n; i++)
    {
        int res = -1;
        for(int j=1; j<=n; j++)
            if(!st[j] && (res==-1 || dist[j] < dist[res])) 
                res = j;

        st[res] = 1;

        for(int j=1; j<=n; j++)
            dist[j] = min(dist[j], dist[res] + g[res][j]);
    }

    if(dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}

int main()
{
    cin >> n >> m;
    memset(g, 0x3f, sizeof g);

    for(int i=1; i<=n; i++) cin >> wait[i];
    wait[n] = 0;

    for(int i=1; i<=m; i++)
    {
        int u, v, c;
        cin >> u >> v >> c;
        if(u == v)
        {
            g[u][v] = g[v][u] = 0;
            continue;
        }
        g[u][v] = min(g[u][v], c + wait[v]);
        g[v][u] = min(g[v][u], c + wait[u]);
    }


    cout << dijkstra()  ;

}
acwing849Dijkstra求最短路Ⅰ

题目

image-20230404211915291

代码

// acwing849Dijkstra求最短路Ⅰ
#include<iostream>
#include<cstring>
using namespace std;

const int N = 5e2+10;
const int M = 1e5+10;

int g[N][N];
int dist[N];
bool st[N];
int n, m;

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);

    dist[1] = 0;

    for(int i=1; i<=n; i++)
    {
        int res = -1;
        for(int j=1; j<=n; j++)
            if(!st[j] && (res==-1 || dist[j] < dist[res])) 
                res = j;

        st[res] = 1;

        for(int j=1; j<=n; j++)
            dist[j] = min(dist[j], dist[res] + g[res][j]);
    }

    if(dist[n] == 0x3f3f3f3f) return -1;
    else dist[n];
}

int main()
{
    memset(g, 0x3f, sizeof g);
    cin >> n >> m;
    for(int i=1; i<=m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        if(a!=b) g[a][b] = min(g[a][b], c);
    }

    int t = dijkstra();

    cout << t;
}
acwing850dijkstra求最短路Ⅱ

题目

image-20230405204425110

代码

// acwing850Dijkstra求最短路Ⅱ
#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 200010;

int h[N], e[N], ne[N], w[N], idx;
int dist[N];
bool st[N];
int n, m;



int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});

    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.second, dis = t.first;
        if(st[ver]) continue;
        st[ver] = 1;
        
        for(int i=h[ver]; i!=-1; i=ne[i])
        {
            int j = e[i];
            if(dist[j] > dis + w[i])
            {
                dist[j] = dis + w[i];
                heap.push({dist[j], j});
            }   
        }
    }

    if(dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

int main()
{
    memset(h, -1, sizeof h);

    cin >> n >> m;
    
    for(int i=1; i<=m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
    }

    int t = dijkstra();

    cout << t;
}

8.4 Floyd求最短路

acwing854Floyd求最短路

题目

image-20230405211503442

代码

// acwing854Floyd求最短路
#include<iostream>
#include<cstring>
using namespace std;

const int N = 210, INF = 1e9;
int d[N][N];
int n, m, k;

void init()
{
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
        {
            if(i == j) d[i][j] = 0;
            else d[i][j] = INF;
        }
}

void floyd()
{
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

int main()
{
    cin >> n >> m >> k;
    
    init();
    
    while(m--)
    {
        int x, y, z;
        cin >> x >> y >> z;
        d[x][y] = min(d[x][y], z);
    }

    floyd();

    while(k--)
    {
        int x, y;
        cin >> x >> y;
        if(d[x][y] > INF/2) cout << "impossible" << endl;
        else cout << d[x][y] << endl;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

introversi0n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值