【PTA数据结构 | C语言版】欧拉回路

发布于:2025-07-23 ⋅ 阅读:(12) ⋅ 点赞:(0)

本专栏持续输出数据结构题目集,欢迎订阅。

文章目录

题目

本题请你编写程序,输出给定无向连通图中的欧拉回路。

输入格式:
输入首先在第一行给出图中最大顶点数量,即正整数 kMaxVertex(≤20)。
第二行给出两个正整数,依次为当前要创建的图的顶点数 n 和边数 m(保证顶点数至少为 3 且不超过最大顶点数量)。
随后 m 行,每行给出一条无向边的两个端点的编号。顶点编号从 0 开始,编号间以 1 个空格分隔。
题目保证没有边被重复给出,并且图一定是连通的。

输出格式:
如果欧拉回路不存在,在一行中输出 No Euler circuit.。
如果欧拉回路存在,在一行中按以下格式输出:

0->v1->v2->...->0

其中 v1、v2 等为欧拉回路途径的顶点编号。注意回路必须从编号为 0 的顶点开始,并以回到编号为 0 的顶点结束。

输入样例 1:
20
12 21
1 3
1 4
2 3
2 8
3 4
3 6
3 7
3 9
4 5
4 7
4 10
4 11
5 10
6 9
7 9
7 10
8 9
9 0
9 10
10 11
10 0

输出样例 1:
0->10->7->9->8->2->3->4->1->3->9->6->3->7->4->5->10->11->4->10->9->0

注意:欧拉回路的输出顺序是不唯一的,以任何顺序输出都可以,有特殊裁判程序判断输出的正确性。例如下列输出也是正确的。

0->9->10->5->4->3->1->4->7->9->8->2->3->6->9->3->7->10->11->4->10->0

输入样例 2:
20
4 5
0 1
1 2
2 3
3 0
2 0

输出样例 2:
No Euler circuit.

代码

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

#define MAX_VERTEX 20

typedef struct Node {
    int vertex;
    struct Node* next;
} Node;

typedef struct {
    Node* adj[MAX_VERTEX];
    int n;
} Graph;

typedef struct {
    int data[MAX_VERTEX * MAX_VERTEX];
    int top;
} Stack;

// 函数声明
void initGraph(Graph* g, int n);
void addEdge(Graph* g, int src, int dest);
int isEulerian(Graph* g);
void findEulerCircuit(Graph* g);
void initStack(Stack* s);
void push(Stack* s, int v);
int pop(Stack* s);
int isEmpty(Stack* s);
int peek(Stack* s);

int main() {
    int kMaxVertex;
    scanf("%d", &kMaxVertex);
    
    int n, m;
    scanf("%d %d", &n, &m);
    
    Graph g;
    initGraph(&g, n);
    
    for (int i = 0; i < m; i++) {
        int src, dest;
        scanf("%d %d", &src, &dest);
        addEdge(&g, src, dest);
    }
    
    if (!isEulerian(&g)) {
        printf("No Euler circuit.\n");
    } else {
        findEulerCircuit(&g);
    }
    
    return 0;
}

// 初始化图
void initGraph(Graph* g, int n) {
    g->n = n;
    for (int i = 0; i < n; i++) {
        g->adj[i] = NULL;
    }
}

// 添加无向边
void addEdge(Graph* g, int src, int dest) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->vertex = dest;
    newNode->next = g->adj[src];
    g->adj[src] = newNode;
    
    newNode = (Node*)malloc(sizeof(Node));
    newNode->vertex = src;
    newNode->next = g->adj[dest];
    g->adj[dest] = newNode;
}

// 检查是否所有顶点度数为偶数
int isEulerian(Graph* g) {
    for (int i = 0; i < g->n; i++) {
        int degree = 0;
        Node* temp = g->adj[i];
        while (temp != NULL) {
            degree++;
            temp = temp->next;
        }
        if (degree % 2 != 0) {
            return 0; // 存在奇度顶点,不是欧拉图
        }
    }
    return 1; // 所有顶点度数均为偶数
}

// 初始化栈
void initStack(Stack* s) {
    s->top = -1;
}

// 入栈
void push(Stack* s, int v) {
    s->data[++(s->top)] = v;
}

// 出栈
int pop(Stack* s) {
    return s->data[(s->top)--];
}

// 检查栈是否为空
int isEmpty(Stack* s) {
    return s->top == -1;
}

// 获取栈顶元素
int peek(Stack* s) {
    return s->data[s->top];
}

// 查找并输出欧拉回路
void findEulerCircuit(Graph* g) {
    // 复制邻接表用于删除边
    Node* adjCopy[MAX_VERTEX];
    for (int i = 0; i < g->n; i++) {
        adjCopy[i] = NULL;
        Node* temp = g->adj[i];
        while (temp != NULL) {
            Node* newNode = (Node*)malloc(sizeof(Node));
            newNode->vertex = temp->vertex;
            newNode->next = adjCopy[i];
            adjCopy[i] = newNode;
            temp = temp->next;
        }
    }
    
    Stack stack;
    initStack(&stack);
    Stack circuit;
    initStack(&circuit);
    
    push(&stack, 0); // 从顶点0开始
    
    while (!isEmpty(&stack)) {
        int u = peek(&stack);
        
        if (adjCopy[u] == NULL) {
            // 如果当前顶点没有邻接边,加入回路
            push(&circuit, pop(&stack));
        } else {
            // 否则选择一个邻接顶点,删除边,继续DFS
            int v = adjCopy[u]->vertex;
            push(&stack, v);
            
            // 在u的邻接表中删除v
            Node* temp = adjCopy[u];
            adjCopy[u] = adjCopy[u]->next;
            free(temp);
            
            // 在v的邻接表中删除u
            Node* prev = NULL;
            temp = adjCopy[v];
            while (temp != NULL && temp->vertex != u) {
                prev = temp;
                temp = temp->next;
            }
            if (prev == NULL) {
                adjCopy[v] = temp->next;
            } else {
                prev->next = temp->next;
            }
            free(temp);
        }
    }
    
    // 输出欧拉回路
    int first = 1;
    while (!isEmpty(&circuit)) {
        if (!first) {
            printf("->");
        }
        printf("%d", pop(&circuit));
        first = 0;
    }
    printf("\n");
    
    // 释放复制的邻接表内存
    for (int i = 0; i < g->n; i++) {
        Node* temp = adjCopy[i];
        while (temp != NULL) {
            Node* next = temp->next;
            free(temp);
            temp = next;
        }
    }
}    

网站公告

今日签到

点亮在社区的每一天
去签到