多源点的最短路径问题

1、车间检查---cdoj3164

多源点最短路径 (Multiple Source Shortest Path)问题

定义:计算从多个源点到图中所有其他节点的最短路径。(Dijkstra是算一个源点到其他节点的最短路径)。

方法:一种常见的方法是添加一个虚拟节点 S,并将这个节点连接到所有的源点,边的权重为零。然后使用单源最短路径算法(如Dijkstra或Bellman-Ford算法)计算从这个虚拟节点出发的最短路径[ 想成其他节点到这个虚拟节点的距离,后续更好理解 ]。

解题思路:

关于本题,可以抽象为:生产相同零件的车间算做一个虚拟节点S'(就是将生产相同零件的车间用权值为0的边连接起来,连接后的整体看做一个虚拟节点。ps:并不是真正的连接,只是在后续使用BFS入队时,生产相同零件的车间一起入队即可)。有K个不同零件,则有K种不同的虚拟节点。然后遍历每一个虚拟节点,

关于建图方式。路径权值都是1,无向图。所以我们可以采取BFS的方式(因为权值为1,用这个简单点)——>就会使用到队列,就自然而然地想到使用vector的方式进行建图,并用一个Bool vis数组表示节点是否被访问过。【如果有不同权值,就要考虑用dij算法了】。并将结果保存

经过bfs求出了每一个虚拟节点到其他节点的的最短路径。然后根据题意我们要算最短开销(看下面的样例进行解释)。

输入样例:
7 6 3 2
1 2 3 3 2 2 1
1 2
2 3
3 4
2 5
5 6
6 7
​
邻接表存图:
adj = {
    0: [1],
    1: [0, 2, 4],
    2: [1, 3],
    3: [2],
    4: [1, 5],
    5: [4, 6],
    6: [5]
}
​
BFS结果:(各个节点到虚拟节点的距离)
color_to_distances[1] = [0, 1, 2, 3, 2, 1, 0]
color_to_distances[2] = [1, 0, 1, 2, 0, 0, 1]
color_to_distances[3] = [2, 1, 0, 0, 2, 3, 4]
​
计算最小开销:
​
一号车间:看第一竖行,分别表示了1号车间到1,2,3号虚拟节点的距离,0+1=1
二号车间:看第二竖行,分别表示了2号车间到1,2,3号虚拟节点的距离,0+1=1
……………………
五号车间:看第五竖行,分别表示了5号车间到1,2,3号虚拟节点的距离,0+2=2
六号车间:看第六竖行,分别表示了6号车间到1,2,3号虚拟节点的距离,0+1=1
七号车间:看第七竖行,分别表示了7号车间到1,2,3号虚拟节点的距离,0+1=1
​
最终结果:
1
1
1
2
2
1
1

代码实现:

需要一个bfs函数,一个min_cost函数,一个main函数。

#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,k,s;
vector<int> bfs(const vector<vector<int>>& adj, const vector<int>& sources){
    vector<int> dist(n, -1);  // 初始化距离数组,-1表示未访问
    queue<int> q;
​
    // 将所有起点加入队列
    for (int source : sources) {
        dist[source] = 0;
        q.push(source);
    }
​
    // BFS遍历
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int v : adj[u]) {
            if (dist[v] == -1) {  // 如果 v 尚未访问
                dist[v] = dist[u] + 1;
                q.push(v);
            }
        }
    }
​
    return dist;
}
vector<int> min_cost( const vector<int>& colors, const vector<pair<int, int>>& edges){
    //处理为无向图
    vector<vector<int>> adj(n);  // 图的邻接表表示
    for (const auto& edge : edges) {
        adj[edge.first].push_back(edge.second);
        adj[edge.second].push_back(edge.first);
    }
    //处理k个虚拟节点
    vector<vector<int>> color_to_distances(k + 1, vector<int>(n, -1));//存储到其他节点到虚拟节点的距离
    for (int c = 1; c <= k; ++c) {      //遍历每一种颜色
        vector<int> sources;        //每次都重新初始化了sources,清空了上一个颜色的车间
        for (int i = 0; i < n; ++i) {    //遍历每一个节点看是不是这种颜色,从而确保同种颜色,一次性入vector
            if (colors[i] == c) {
                sources.push_back(i);
            }
        }
        if (!sources.empty()) {        //如果sources不是空,就执行
            color_to_distances[c] = bfs(adj, sources);  // 计算每种颜色的最短距离
        }
    }
​
    //计算最小开销
    vector<int> result(n, 0);
    for (int i = 0; i < n; ++i) {              //遍历每个节点
        vector<int> distances;
        for (int c = 1; c <= k; ++c) {           //遍历每个颜色
            if (color_to_distances[c][i] != -1) {  // 如果有距离记录
                distances.push_back(color_to_distances[c][i]);
            }
        }
        sort(distances.begin(), distances.end());  // 排序距离
        for (int j = 0; j < s && j < distances.size(); ++j) {
            result[i] += distances[j];  // 取最小的 s 个距离求和
        }
    }
​
    return result;
}
int main(){
    cin>>n>>m>>k>>s;
    vector<int> color(n);   //初始化n个int类型的用于存生产零件类型,将一种零件看做一个color
    for(int i=0;i<n;i++){
        cin>>color[i];
    }
    //读入边信息
    vector<pair<int,int>> edge(m);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edge[i] = {u - 1, v - 1};  // 假设输入的节点编号是从1开始的,转换为从0开始
    }
    vector<int> result = min_cost( color, edge);
​
    for (int cost : result) {
        cout << cost << endl;
    }
​
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雙溪舴艋舟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值