简体   繁体   English

在具有附加条件的图中找到最小加权路径

[英]Find the minimum weighted path in a graph with additional conditions

I have a problem as below and I am really stuck with it as it run with more than the time I desired (about 1 second).我有一个问题如下,我真的坚持它,因为它运行的时间超过了我想要的时间(大约 1 秒)。 I really want your help to build up a more efficient algorithms than mine我真的希望你能帮助我建立一个比我更高效的算法

Given an undirected graph G = (V, E) with two parameter of weights w1 and w2 for each edges.给定一个无向图 G = (V, E),每条边有两个权重 w1 和 w2 参数。 This graph has N vertices and M edges.该图有 N 个顶点和 M 条边。 A K-Elementary path S is a sub-graph of G which must be an elementary graph and it does have exactly K edges. K 基本路径 S 是 G 的子图,它必须是基本图并且确实有 K 条边。

Find a K-elementary path S with the sum of w1 of all edges as minimum value and the sum of w2 of all edges of S must be smaller than a given value Q. If it does not exist any path satisfied, print out the value -1求一条K-基本路径S,其中所有边的w1之和为最小值,S的所有边的w2之和必须小于给定值Q。如果不存在任何满足的路径,则打印出该值-1

Input:输入:

The first line with four values N, M, K, Q (2 <= N, K <= 50, 1 <= M <= 2*N, 1 <= Q <= 10^9)第一行有四个值 N, M, K, Q (2 <= N, K <= 50, 1 <= M <= 2*N, 1 <= Q <= 10^9)

The next M lines show the edges of the graph: V1 V2 W1 W2 (1 <= V1, V2 <= N, 1 <= W1 <= 10^4, 1 <= W2 <= 10^4)接下来的 M 行显示了图形的边缘:V1 V2 W1 W2 (1 <= V1, V2 <= N, 1 <= W1 <= 10^4, 1 <= W2 <= 10^4)

Output: One integer to show the minimum weight of the k-elementary graph found. Output:一个 integer 显示找到的 k-初等图的最小权重。 -1 if non-exists -1 如果不存在

Sample test case:示例测试用例:

Input:输入:

 5 7 3 6 1 2 1 2 1 4 2 2 1 5 3 6 2 3 3 2 2 4 4 4 3 4 5 1 4 5 4 7

Output: Output:

 6

First of all, I want to quote the definition of an elementary path .首先,我想引用一个基本路径的定义。

In short, for this problem, we need to find an k-elementary path S such that the weight to w1 is minimum, the sum of all edges to w2 is less than or equal to Q and it does have exactly K edges.简而言之,对于这个问题,我们需要找到一条 k 基本路径 S,使得到 w1 的权重最小,到 w2 的所有边的总和小于或等于 Q,并且它确实有 K 条边。

I do have a Backtracking approach, in which I tried to build up all the graph satisfying the second condition (w2) and then find the minimum of the first condition (w1) but, as you have known, the time complexity is quite high.我确实有一种回溯方法,我尝试构建所有满足第二个条件 (w2) 的图,然后找到第一个条件 (w1) 的最小值,但是,如您所知,时间复杂度非常高。 However, I find it hard to convert it to dynamic programming or any other methods to reduce to time complexity.但是,我发现很难将其转换为动态规划或任何其他方法来降低时间复杂度。 I do add some Branch-bound condition but it is still slow.我确实添加了一些 Branch-bound 条件,但它仍然很慢。

Below is my source code which you can refer but I do not think it is useful以下是我的源代码,您可以参考,但我认为它没有用

#include <bits/stdc++.h>
using namespace std;
#define N 51
#define INF 1e9
int n, m, K, Q;
bool appear[N];
int W1[N][N];
int W2[N][N];
int currentSum1 = 0;
int currentSum2 = 0;
int source = 0;
int res = INF;
int Log[N];
int minElement = INF;
bool check(int k, int v)
{
    return !appear[v] && W1[Log[k - 1]][v] != 0 && W2[Log[k - 1]][v] != 0;
}
void solution()
{
    if(currentSum1 != 0 && currentSum1 < res)
    {
        res = currentSum1;
        // for(int i = 0; i <= K; i++)
        //     cout << Log[i] << " ";
        // cout << endl;
    }
}
void solve(int k)
{
    for(int v = 1; v <= n; v++)
    {
        if(check(k, v) && currentSum2 + W2[source][v] <= Q && currentSum1 + (K - k) * minElement <= res) //Branch-bound condition
        {
            Log[k] = v;
            currentSum2 += W2[Log[k - 1]][v];
            currentSum1 += W1[Log[k - 1]][v];
            appear[v] = true;
            if(k == K)
                solution();
            else
                solve(k + 1);
            currentSum1 -= W1[Log[k - 1]][v];
            currentSum2 -= W2[Log[k - 1]][v];
            appear[v] = false;
        }
    }
}
int main()
{
    fast;
    // freopen("data.txt", "r", stdin);
    cin >> n >> m >> K >> Q;
    for(int i = 0; i < m; i++)
    {
        int x, y, w1, w2;
        cin >> x >> y >> w1 >> w2;
        minElement = min(minElement, w1);
        W1[x][y] = w1;
        W1[y][x] = w1;
        W2[x][y] = w2;
        W2[y][x] = w2;
    }
    for(int v = 1; v <= n; v++)
    {
        source = v;
        currentSum2 = 0;
        currentSum1 = 0;
        Log[0] = v;
        for(int i = 1; i <= n; i++)
            appear[i] = false;
        appear[source] = true;
        solve(1);
    }
    if(res != INF)
        cout << res << endl;
    else 
        cout << -1 << endl;
}

Firstly, finding a resource constrained shortest path is NPHard.首先,寻找资源受限的最短路径是 NPHard。 Most approaches to this problem employ a labelling scheme, which is a specialization of dynamic programming.大多数解决此问题的方法都采用标记方案,这是动态规划的一个特例。 You could use available libraries to accomplish this.您可以使用可用的库来完成此操作。 See here for a boost implementation.请参阅此处以了解升压实施。 This implementation will help you find (possibly) a non-elementary path from s to t as long all of the w_2 weights are positive.只要所有 w_2 权重都是正数,此实现将帮助您找到(可能)从 s 到 t 的非基本路径。 If the weights w_2's are negative, then it is possible that with negative w_1 weights and positive Q, the problem is unbounded.如果权重 w_2 为负数,则 w_1 权重为负数且 Q 为正数时,问题可能是无界的。

Now, coming to the need for a k-elementary shortest path, as far as I know, there is no off-the shelf algorithm that could help accomplish this.现在,需要 k 基本最短路径,据我所知,没有现成的算法可以帮助实现这一点。 First, forget about k.首先,忘记 k。 Finding an elementary shortest path subject to additional resource constraints can be done using the labelling schemed presented in the papers referred to in the boost link above.可以使用上面 boost 链接中提到的论文中提供的标记方案来找到受额外资源限制的基本最短路径。 In this case, the state space of the dynamic program should increase to allow for the storage of the indicator vector of all previously visited nodes in the path.在这种情况下,动态程序的 state 空间应该增加以允许存储路径中所有先前访问过的节点的指示向量。 This make the problem much harder to solve as compared to the basic resource constrained shortest path problem.与基本的资源受限最短路径问题相比,这使得该问题更难解决。

Now, getting to your need of a k-elementary shortest path, one would have to embed the above scheme of finding an elementary shortest path recursively inside another function that keeps checking whether the elementary path returned has k edges or not.现在,为了满足您对 k 基本最短路径的需求,必须将上述递归查找基本最短路径的方案嵌入到另一个 function 中,该方案不断检查返回的基本路径是否具有 k 条边。 If it does have k edges, then you are done.如果它确实有 k 个边,那么你就完成了。 If not, you would have to somehow place restrictions on the algorithm to prevent this particular path.否则,您将不得不以某种方式对算法施加限制以阻止此特定路径。 That can be accomplished by using prelabels.这可以通过使用预标签来实现。 As far as I know, this was first done in this work.据我所知,这是在这项工作中首先完成的。

Good luck, but this problem is doubly/triply difficult (because of possible need for multiple iterations).祝你好运,但这个问题是双重/三重困难的(因为可能需要多次迭代)。 You should refer to the work mentioned in the boost link and subsequent papers in this area to understand the state-of-the-art.您应该参考 boost 链接中提到的工作以及该领域的后续论文,以了解最先进的技术。 I suspect the state-of-the-art to not be able to solve problems beyond 10-15 nodes.我怀疑最先进的技术无法解决超过 10-15 个节点的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM