通过m条边的最短路径



你好,聪明人。

我有一个图形问题。

给定一个具有n个顶点的完整、有向、交错图,求出通过m-1条边(路径中的边可能重复(的最短路径(从任何顶点开始(的长度。至于极限n<=200,m<=1e9.

看看极限,我可以说一定有一些聪明的方法,而不需要一些dp和图遍历,但我想不出这样的方法。提前谢谢。

Example:
n = 3, m = 5
edges:
1 -> 2 weight = 10,
1 -> 3 weight = 100,
2 -> 1 weight = 10,
2 -> 3 weight = 50,
3 -> 1 weight = 30,
3 -> 2 weight = 70,
answer would be 40 (1 -> 2 -> 1 -> 2 -> 1)

一个简单的解决方案是运行BFS(广度优先搜索(,直到第m级别,并保持最小权重总和并返回它。


但在这个问题上,它说我们可以多次包括顶点,直到它们之间有一条路径,所以现在我们可以执行以下步骤:

  1. 计算图中存在的所有循环,我们可以在计算可能的最小权重时重用这些循环

例如:

在这个问题中,存在一个循环1-->2-->1,长度=3,权重=20,m的值=5,现在我们可以使用这个路径两次,但如果m是6,那么我们还有1个节点要包括。


  1. 现在我们可以从1计算长度为l(如果m=6,则为1(的最小路径(包括剩余节点(,并将其添加到上述权重中。(我们将1->2=10(

  • 对图形中的每个循环重复步骤1和2,并保持最小和
  • 下面是描述上述解决方案的c++代码(它可能不是100%正确的,但你会得到基本的想法(

    #include <iostream>
    #include <queue>
    #include <vector>
    using namespace std;
    struct Edge{
    int src, dest, weight;
    };
    struct Node{
    int start_vertex, end_vertex, weight, edge_count=0;
    };
    class Graph{
    public: 
    vector<vector<pair<int, int>>> adjList;
    int V;
    Graph(vector<Edge> edges, int V){
    adjList.resize(V+1);
    this->V = V;
    for(Edge edge:edges){
    adjList[edge.src].push_back({edge.dest, edge.weight});
    }
    }
    };
    int BFS(Graph &g, int m){
    queue<Node> Q;
    vector<Node> cycles;
    // to store min path from vertex i of length j
    vector<vector<int>> dp(g.V+1, vector<int>(g.V+1, INT_MAX));
    for(int i=0; i<=g.V; i++)
    dp[i][0] = 0;
    for(int i=1; i<=g.V; i++){
    Q.push({i, i, 0, 1});
    }
    while(!Q.empty()){
    Node top = Q.front();
    Q.pop();
    if(top.edge_count >= g.V) break;
    int v = top.end_vertex;
    int start_vertex = top.start_vertex;
    int weight = top.weight;
    int edge_count = top.edge_count;
    for(auto x:g.adjList[v]){
    // finding all the cycles
    if(x.first == start_vertex){
    Node n = {start_vertex, v, weight+x.second, edge_count+1};
    cycles.push_back(n);
    }else{
    Q.push({start_vertex, x.first, weight+x.second, edge_count+1});
    }
    
    if(dp[start_vertex][edge_count] > weight+x.second){
    dp[start_vertex][edge_count] = weight+x.second;
    }
    }
    }
    // finding minimum:
    int min_weight = INT_MAX;
    if(m<=g.V){
    for(int i=1; i<=g.V; i++){
    min_weight = min(min_weight, dp[i][m]);
    }
    }
    // checking all the cycles for  reusability and maintaining min sum
    for(int i=0; i<cycles.size(); i++){
    int sum = cycles[i].weight;
    int length_left_to_cover = m-cycles[i].edge_count;
    sum += length_left_to_cover/(cycles[i].edge_count-1) * cycles[i].weight;
    int vertices_left_to_include = 0;
    if(m-cycles[i].edge_count>0){
    vertices_left_to_include = (m-cycles[i].edge_count)%(cycles[i].edge_count-1);
    }
    min_weight = min(min_weight, sum+dp[cycles[i].start_vertex][vertices_left_to_include]);
    }
    return min_weight;
    
    }
    // 1 -> 2 weight = 10,
    // 1 -> 3 weight = 100,
    // 2 -> 1 weight = 10,
    // 2 -> 3 weight = 50,
    // 3 -> 1 weight = 30,
    // 3 -> 2 weight = 70,
    int main(){
    vector<Edge> edges = {
    {1, 2, 10},
    {1, 3, 100},
    {2, 1, 10},
    {2, 3, 50},
    {3, 1, 30},
    {3, 2, 70}
    };
    int V = 3;
    int m = 5;
    Graph g(edges, V);
    cout<<"Min weight: "<<BFS(g, m);
    }
    

    输出:

    Min weight: 40
    

    最新更新