多重加权图消除

huangapple go评论63阅读模式
英文:

Multiple-Weighted Graph Elimination

问题

这是您提供的代码的翻译:

我有一个多权重图。每个节点之间显示从一个城市到另一个城市的路径,每个边都有时间、距离和成本。用户应该输入起点、终点和路径的条件(时间、距离和成本)。一旦程序获取到这些条件,它应该根据所选择的条件从起始节点遍历并删除当前节点和下一个节点之间的冗余节点,直到到达终节点。在这里,冗余节点是指到达最终节点的第二或第三个连接到**相同下一个节点**的节点,其值更差。这里的更差意味着时间更长、成本更高或距离更远。

我尝试了不同的方法,如将其转换为一个单一权重图,使用Dijkstra算法和使用数组来存储边的值,但都没有得到我想要的结果。你能否建议我执行此任务的最高效的时间和空间算法?

这是我编写的其中一个代码。这段代码对1-4的路径有效,但对于其他路径,它显示了错误的结果,调试时我明白问题与当前和next_vertex的值有关

如果您有任何关于这段代码的具体问题或需要进一步的帮助,请随时提问。

英文:

I have a multiple weighted graph. Each between nodes are showing the paths from a city to another city and each edge have a time, distance and cost. The user should enter a start and an end point and a criteria for the path (time, distance, and cost). Once the program get this,it should traverse and remove redundant nodes between a current node and the next while traversing from Starting Node to the Ending Node based on the criteria chosen. Here, a redundant node means that the second or the third connection to the same next node to reach to the final node with worse values. Here, worse means longer time, more costly, or longer distance.
I have tried different methods like converting to a simple one-weighted graph, using Dijkstra and using arrays for storing the edge values but non of them give me the desired output. Can you suggest me the most time and space efficient algorithm to do this task?
this is one of the codes I have written. This code works for path from 1-4 but for the other paths, it shows the wrong result and while debugging I understand that the problem is related to the current and next_vertex value.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX_VERTICES 40
enum color { White, Gray, Black };
typedef struct list_node {
int index;
int time;
int distance;
int cost;
struct list_node* next;
} list_node;
typedef struct node {
int data;
enum color color;
list_node* head;
} node;
typedef struct graph {
int nVertices;
node heads[];
} graph;
node* new_node(int data) {
node* z = (node*)malloc(sizeof(node));
z->data = data;
z->head = NULL;
z->color = White;
return z;
}
list_node* new_list_node(int item_index, int time, int distance, int cost) {
list_node* z = (list_node*)malloc(sizeof(list_node));
z->index = item_index;
z->time = time;
z->distance = distance;
z->cost = cost;
z->next = NULL;
return z;
}
graph* new_graph(int nVertices) {
graph* g = (graph*)malloc(sizeof(graph) + (nVertices * sizeof(node)));
g->nVertices = nVertices;
int i;
for (i = 0; i < nVertices; i++) {
node* z = new_node(-1);
g->heads[i] = *z;
}
return g;
}
void add_node_to_graph(graph* g, int data) {
node* z = new_node(data);
int i;
for (i = 0; i < g->nVertices; i++) {
if (g->heads[i].data < 0) {
g->heads[i] = *z;
break;
}
}
}
int in_graph_head_list(graph* g, int data) {
int i;
for (i = 0; i < g->nVertices; i++) {
if (g->heads[i].data == data)
return 1;
}
return 0;
}
void AddEdges(graph* g, int source, int dest, int time, int distance, int cost) {
if (!in_graph_head_list(g, source)) {
add_node_to_graph(g, source);
}
if (!in_graph_head_list(g, dest)) {
add_node_to_graph(g, dest);
}
int i, j;
for (i = 0; i < g->nVertices; i++) {
if (g->heads[i].data == source) {
int indexDest = -1;
for (j = 0; j < g->nVertices; j++) {
if (g->heads[j].data == dest) {
indexDest = j;
break;
}
}
if (indexDest != -1) {
list_node* n = new_list_node(indexDest, time, distance, cost);
if (g->heads[i].head == NULL) {
g->heads[i].head = n;
}
else {
list_node* temp = g->heads[i].head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = n;
}
}
break;
}
}
}
void printgraph(graph* g) {
int i;
for (i = 0; i < g->nVertices; i++) {
node* curr_node = &(g->heads[i]);
printf("Node %d: ", curr_node->data);
list_node* temp = curr_node->head;
if (temp == NULL) {
printf("No adjacent nodes.\n");
}
else {
while (temp != NULL) {
int adjacent_vertex = g->heads[temp->index].data;
printf("%d (T=%d, D=%d, C=%d)", adjacent_vertex, temp->time, temp->distance, temp->cost);
temp = temp->next;
if (temp != NULL) {
printf(" --> ");
}
}
printf("\n");
}
}
}
void print_updated_graph(graph* g) {
printf("Updated Graph:\n");
for (int i = 0; i < g->nVertices; i++) {
node* curr_node = &(g->heads[i]);
printf("Node %d: ", curr_node->data);
list_node* temp = curr_node->head;
if (temp == NULL) {
printf("No adjacent nodes.\n");
} else {
while (temp != NULL) {
int adjacent_vertex = g->heads[temp->index].data;
printf("%d (T=%d, D=%d, C=%d)", adjacent_vertex, temp->time, temp->distance, temp->cost);
temp = temp->next;
if (temp != NULL) {
printf(" --> ");
}
}
printf("\n");
}
}
}
void eliminate_edges(graph* g, int current, int next_vertex, int choice, int* edge_values) {
node* curr_node = &(g->heads[current - 1]); // Adjusted for 0-based indexing
list_node* temp = curr_node->head;
list_node* prev = NULL;
while (temp != NULL) {
int adjacent_vertex = temp->index + 1; // Adjusted for 1-based indexing
// Check if the adjacent vertex is not the next_vertex
if (adjacent_vertex != next_vertex + 1) {
// Check the chosen weight for elimination
switch (choice) {
case 1: // Time
if (temp->time >= edge_values[0]) {
if (prev == NULL) {
curr_node->head = temp->next;
} else {
prev->next = temp->next;
}
free(temp);
} else {
prev = temp;
}
break;
case 2: // Distance
if (temp->distance > edge_values[1]) { // Use > instead of >=
if (prev == NULL) {
curr_node->head = temp->next;
} else {
prev->next = temp->next;
}
free(temp);
} else {
prev = temp;
}
break;
case 3: // Cost
if (temp->cost >= edge_values[2]) {
if (prev == NULL) {
curr_node->head = temp->next;
} else {
prev->next = temp->next;
}
free(temp);
} else {
prev = temp;
}
break;
}
}
temp = temp->next;
}
}
void find_path(graph* g, int current, int end, int* visited, int* path, int path_length, int choice) {
visited[current] = 1;
path[path_length] = current;
path_length++;
if (current == end) {
// Found a path from start to end
printf("Path: ");
for (int i = 0; i < path_length - 1; i++) {
printf("%d ", path[i]);
}
printf("%d\n", path[path_length - 1]);
// Print edge values
for (int i = 0; i < path_length - 1; i++) {
node* curr_node = &(g->heads[path[i] - 1]);
list_node* temp = curr_node->head;
while (temp != NULL) {
if (temp->index + 1 == path[i + 1]) {
printf("Edge (%d, %d): (T=%d, D=%d, C=%d)\n", path[i], path[i + 1], temp->time, temp->distance, temp->cost);
break;
}
temp = temp->next;
}
}
printf("\n");
} else {
node* curr_node = &(g->heads[current - 1]); // Adjusted for 0-based indexing
list_node* temp = curr_node->head;
int next_vertex = temp->index + 1; // Adjusted for 1-based indexing
int* path_visited = calloc(g->nVertices + 1, sizeof(int)); // Array to track visited vertices within the current path
int multiple_paths = 0; // Variable to track multiple paths
int edge_values[3] = { INT_MAX, INT_MAX, INT_MAX }; // Array to store edge values for comparison
while (temp != NULL) {
int adjacent_vertex = temp->index + 1; // Adjusted for 1-based indexing
if (!visited[adjacent_vertex]) {
if (path_visited[adjacent_vertex]) {
multiple_paths = 1;
break;
}
path_visited[adjacent_vertex] = 1;
next_vertex++;
// Store edge values for comparison
if (temp->time < edge_values[0])
edge_values[0] = temp->time;
if (temp->distance < edge_values[1])
edge_values[1] = temp->distance;
if (temp->cost < edge_values[2])
edge_values[2] = temp->cost;
}
temp = temp->next;
}
// Check if there are multiple paths from the current vertex to the next adjacent vertex
if (multiple_paths) {
eliminate_edges(g, current, next_vertex, choice, edge_values);
}
temp = curr_node->head; // Reset the temp pointer
while (temp != NULL) {
int adjacent_vertex = temp->index + 1; // Adjusted for 1-based indexing
if (!visited[adjacent_vertex]) {
find_path(g, adjacent_vertex, end, visited, path, path_length, choice);
}
temp = temp->next;
}
free(path_visited);
}
visited[current] = 0;
path_length--;
}
int main() {
graph* g = new_graph(4);
printf("Welcome to the trip graph.\n");
printf("The trip roads are as below.\n\n");
AddEdges(g, 1, 2, 1, 1, 1);
AddEdges(g, 1, 3, 1, 1, 1);
AddEdges(g, 2, 4, 1, 4, 5);
AddEdges(g, 2, 3, 3, 2, 1);
AddEdges(g, 2, 1, 2, 1, 3);
AddEdges(g, 3, 1, 7, 1, 4);
AddEdges(g, 3, 1, 1, 3, 2);
AddEdges(g, 3, 4, 4, 3, 1);
AddEdges(g, 3, 4, 1, 7, 6);
AddEdges(g, 4, 4, 5, 3, 2);
AddEdges(g, 4, 3, 1, 1, 1);
AddEdges(g, 4, 2, 1, 4, 5);
printgraph(g);
int start, end;
while (1) {
printf("\nEnter your starting Node for elimination (press -1 to exit): ");
scanf("%d", &start);
if (start == -1) {
break;
}
printf("Enter the ending node: ");
scanf("%d", &end);
int choice;
while (1) {
printf("\nBased on what do you want to do the elimination?\n");
printf("1. Time 2. Distance 3. Cost\n");
scanf("%d", &choice);
printf("\nAll paths from %d to %d:\n", start, end);
if (choice >= 1 && choice <= 3) {
break;
} else {
printf("Invalid choice. Please try again.\n");
}
}
int* visited = calloc(g->nVertices + 1, sizeof(int)); // Array to track visited vertices
int* path = calloc(g->nVertices + 1, sizeof(int)); // Array to store the current path
find_path(g, start, end, visited, path, 0, choice);
free(visited);
free(path);
print_updated_graph(g); 
}
return 0;
}

答案1

得分: 1

这是我解决问题的方法:

  • 定义一个包含有关边信息的结构。
  • 声明并初始化该结构的数组。
  • 首先按源,然后按目的地,最后按用户选择的值对数组进行排序。
  • 然后遍历数组,仅对用户选择的边调用 addEdge。将边添加到图时,边的权重是用户选择的参数。
  • 现在你有一个简单的图,每个给定的源和目的地之间只有一条边,你可以对图应用路径查找算法。

以下是演示这些概念的代码。addEdge 函数只是简单地打印选定的边,而不是将它们添加到图中。完整代码会将边添加到图中,找到最佳路径,然后打印结果。

#include <stdio.h>
#include <stdlib.h>

enum { 按时间排序, 按距离排序, 按成本排序, 无效选择 };

typedef struct Edge
{
    int ;
    int 目的地;
    int 时间;
    int 距离;
    int 成本;
} Edge;

int 比较边(const Edge *1, const Edge *2, int 选择)
{
    // 如果源不同,具有较低源索引的边排在前面
    if (1-> != 2->)
        return (1-> > 2->) - (1-> < 2->);

    // 如果目的地不同,具有较低目的地索引的边排在前面
    if (1->目的地 != 2->目的地)
        return (1->目的地 > 2->目的地) - (1->目的地 < 2->目的地);

    // 否则根据用户选择的标准排序
    switch (选择)
    {
        case 按时间排序:     return (1->时间 > 2->时间) - (1->时间 < 2->时间);
        case 按距离排序: return (1->距离 > 2->距离) - (1->距离 < 2->距离);
        case 按成本排序:     return (1->成本 > 2->成本) - (1->成本 < 2->成本);
        default:               return 0; // 不应该发生,但编译器需要这个
    }
}

int 按时间比较(const void *指针1, const void *指针2)
{
    return 比较边(指针1, 指针2, 按时间排序);
}

int 按距离比较(const void *指针1, const void *指针2)
{
    return 比较边(指针1, 指针2, 按距离排序);
}

int 按成本比较(const void *指针1, const void *指针2)
{
    return 比较边(指针1, 指针2, 按成本排序);
}

int 获取用户选择(void)
{
    printf("根据什么条件进行消除?\n");
    printf("1. 时间 2. 距离 3. 成本\n");
    int 选择;
    if (scanf("%d", &选择) != 1)
        return 无效选择;
    switch (选择)
    {
        case 1: return  按时间排序;
        case 2: return  按距离排序;
        case 3: return  按成本排序;
        default: return 无效选择;
    }
}

void 添加边(Edge *, int 选择)
{
    // 打印源,目的地和选择的权重
    // 在完整代码中,这将向图添加源,目的地和权重
    switch (选择)
    {
        case 按时间排序:      printf("%d->%d: %d\n", ->, ->目的地, ->时间);       break;
        case 按距离排序:  printf("%d->%d: %d\n", ->, ->目的地, ->距离);   break;
        case 按成本排序:      printf("%d->%d: %d\n", ->, ->目的地, ->成本);       break;
    }
}

int 主函数(void)
{
    static Edge 边缘列表[] =
    {
        { 1, 2, 1, 1, 1 },
        { 1, 3, 1, 1, 1 },
        { 2, 4, 1, 4, 5 },
        { 2, 3, 3, 2, 1 },
        { 2, 1, 2, 1, 3 },
        { 3, 1, 7, 1, 4 },
        { 3, 1, 1, 3, 2 },
        { 3, 4, 4, 3, 1 },
        { 3, 4, 1, 7, 6 },
        { 4, 4, 5, 3, 2 },
        { 4, 3, 1, 1, 1 },
        { 4, 2, 1, 4, 5 },
    };
    int 边缘数 = sizeof(边缘列表) / sizeof(边缘列表[0]);

    while (1)
    {
        int 选择 = 获取用户选择();

        // 根据用户的选择对边进行排序
        switch (选择)
        {
            case 按时间排序:      qsort(边缘列表, 边缘数, sizeof(Edge), 按时间比较);     break;
            case 按距离排序:  qsort(边缘列表, 边缘数, sizeof(Edge), 按距离比较); break;


<details>
<summary>英文:</summary>

Here&#39;s how I would approach the problem:
 - Define a structure that contains information about an edge.
 - Declare and initialize an array of those structures.
 - Sort the array first by source, then by destination, then by the value that the user has chosen.
 - Then go through the array, and only call `addEdge` for those edges that the user has chosen. When adding an edge to the graph, the weight for the edge is the parameter chosen by the user.
 - Now you have a simple graph with only a single edge between any given source and destination, and you can apply the path-finding algorithm to the graph.

The code below demonstrates these concepts. The `addEdge` function simply prints the chosen edges, rather than adding them to the graph. The full code would add the edges to the graph, find the best path, and then print the results.

```C
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

enum { SORT_BY_TIME, SORT_BY_DISTANCE, SORT_BY_COST, INVALID_CHOICE };

typedef struct Edge
{
    int source;
    int dest;
    int time;
    int distance;
    int cost;
} Edge;

int compareEdges(const Edge *edge1, const Edge *edge2, int choice)
{
    // if the sources are different, the edge with the lower source index is first
    if (edge1-&gt;source != edge2-&gt;source)
        return (edge1-&gt;source &gt; edge2-&gt;source) - (edge1-&gt;source &lt; edge2-&gt;source);

    // if the destinations are different, the edge with the lower destination index is first
    if (edge1-&gt;dest != edge2-&gt;dest)
        return (edge1-&gt;dest &gt; edge2-&gt;dest) - (edge1-&gt;dest &lt; edge2-&gt;dest);

    // otherwise sort based on the user-selected criteria
    switch (choice)
    {
        case SORT_BY_TIME:     return (edge1-&gt;time &gt; edge2-&gt;time) - (edge1-&gt;time &lt; edge2-&gt;time);
        case SORT_BY_DISTANCE: return (edge1-&gt;distance &gt; edge2-&gt;distance) - (edge1-&gt;distance &lt; edge2-&gt;distance);
        case SORT_BY_COST:     return (edge1-&gt;cost &gt; edge2-&gt;cost) - (edge1-&gt;cost &lt; edge2-&gt;cost);
        default:               return 0; // should never happen, but the compiler needs this
    }
}

int compareByTime(const void *ptr1, const void *ptr2)
{
    return compareEdges(ptr1, ptr2, SORT_BY_TIME);
}

int compareByDistance(const void *ptr1, const void *ptr2)
{
    return compareEdges(ptr1, ptr2, SORT_BY_DISTANCE);
}

int compareByCost(const void *ptr1, const void *ptr2)
{
    return compareEdges(ptr1, ptr2, SORT_BY_COST);
}

int getUserChoice(void)
{
    printf(&quot;\nBased on what do you want to do the elimination?\n&quot;);
    printf(&quot;1. Time 2. Distance 3. Cost\n&quot;);
    int choice;
    if (scanf(&quot;%d&quot;, &amp;choice) != 1)
        return INVALID_CHOICE;
    switch (choice)
    {
        case 1: return  SORT_BY_TIME;
        case 2: return  SORT_BY_DISTANCE;
        case 3: return  SORT_BY_COST;
        default: return INVALID_CHOICE;
    }
}

void addEdge(Edge *edge, int choice)
{
    // print the source, destination, and chosen weight
    // in the full code, this would add the source, destination, and weight to the graph
    switch (choice)
    {
        case SORT_BY_TIME:      printf(&quot;%d-&gt;%d: %d\n&quot;, edge-&gt;source, edge-&gt;dest, edge-&gt;time);       break;
        case SORT_BY_DISTANCE:  printf(&quot;%d-&gt;%d: %d\n&quot;, edge-&gt;source, edge-&gt;dest, edge-&gt;distance);   break;
        case SORT_BY_COST:      printf(&quot;%d-&gt;%d: %d\n&quot;, edge-&gt;source, edge-&gt;dest, edge-&gt;cost);       break;
    }
}

int main(void)
{
    static Edge edgeList[] =
    {
        { 1, 2, 1, 1, 1 },
        { 1, 3, 1, 1, 1 },
        { 2, 4, 1, 4, 5 },
        { 2, 3, 3, 2, 1 },
        { 2, 1, 2, 1, 3 },
        { 3, 1, 7, 1, 4 },
        { 3, 1, 1, 3, 2 },
        { 3, 4, 4, 3, 1 },
        { 3, 4, 1, 7, 6 },
        { 4, 4, 5, 3, 2 },
        { 4, 3, 1, 1, 1 },
        { 4, 2, 1, 4, 5 },
    };
    int edgeCount = sizeof(edgeList) / sizeof(edgeList[0]);

    while (1)
    {
        int choice = getUserChoice();

        // sort the edges based on the user&#39;s choice
        switch (choice)
        {
            case SORT_BY_TIME:      qsort(edgeList, edgeCount, sizeof(Edge), compareByTime);     break;
            case SORT_BY_DISTANCE:  qsort(edgeList, edgeCount, sizeof(Edge), compareByDistance); break;
            case SORT_BY_COST:      qsort(edgeList, edgeCount, sizeof(Edge), compareByCost);     break;
            default: printf(&quot;bye\n&quot;); exit(1);
        }

        // add the chosen edges to the graph 
        addEdge(&amp;edgeList[0], choice);
        int used = 0;
        for (int i = 1; i &lt; edgeCount; i++)
            if (edgeList[i].source != edgeList[used].source || (edgeList[i].source == edgeList[used].source &amp;&amp; edgeList[i].dest != edgeList[used].dest))
            {
                addEdge(&amp;edgeList[i], choice);
                used = i;
            }
    }
}

Here's a sample run of the program. Note that only edges 3-&gt;1 and 3-&gt;4 have multiple edges to choose from. I've highlighted those with comments.

Based on what do you want to do the elimination?
1. Time 2. Distance 3. Cost
1
1-&gt;2: 1
1-&gt;3: 1
2-&gt;1: 2
2-&gt;3: 3
2-&gt;4: 1
3-&gt;1: 1   // best time for 3-&gt;1 is 1
3-&gt;4: 1   // best time for 3-&gt;4 is 1
4-&gt;2: 1
4-&gt;3: 1
4-&gt;4: 5
Based on what do you want to do the elimination?
1. Time 2. Distance 3. Cost
2
1-&gt;2: 1
1-&gt;3: 1
2-&gt;1: 1
2-&gt;3: 2
2-&gt;4: 4
3-&gt;1: 1   // best distance for 3-&gt;1 is 1
3-&gt;4: 3   // best distance for 3-&gt;4 is 3
4-&gt;2: 4
4-&gt;3: 1
4-&gt;4: 3
Based on what do you want to do the elimination?
1. Time 2. Distance 3. Cost
3
1-&gt;2: 1
1-&gt;3: 1
2-&gt;1: 3
2-&gt;3: 1
2-&gt;4: 5
3-&gt;1: 2   // best cost for 3-&gt;1 is 2
3-&gt;4: 1   // best cost for 3-&gt;1 is 1
4-&gt;2: 5
4-&gt;3: 1
4-&gt;4: 2
Based on what do you want to do the elimination?
1. Time 2. Distance 3. Cost
4
bye

Notes about indexing:

  • convert from 1-based indexing to 0-based indexing in addEdge
  • convert from 0-based indexing to 1-based indexing in printGraph
  • all of the path-finding code should be using 0-based indexing.

In my code, the addEdge function is doing the printing, so there are no conversions anywhere in the code.

huangapple
  • 本文由 发表于 2023年6月9日 02:46:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76434870.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定