作业9——图

1. 图的基本操作–图的深度优先和广度优先遍历
//
// Created by lct2023 on 2024/5/26.
//
#include <stdio.h>

#include <stdlib.h>

#define max_vertex_num 100 //最多顶点个数

typedef char VertexData;

typedef int AdjType;

typedef int OtherInfo;

int visisted[max_vertex_num] = {0}; //供深度优先遍历使用

int visisted1[max_vertex_num] = {0};//供广度优先遍历使用


typedef struct Node
{

    int adjvex;  //定义该弧指向顶点的位置

    struct Node *nextarc; //定义下一条弧上网指针

} Node;


typedef struct VVertexNode
{

    char data; //定义顶点的数据

    Node *firstarc;  //定义该顶点第一条弧的指针

} VertexNode[max_vertex_num];


typedef struct
{

    VertexNode vertex;
	int vexnum, arcnum;

} AdjList;  //定义邻接表



int LocateVertex(AdjList *G, VertexData v)  //求顶点的位置

{

    int j = -1, k;

    for (k = 0; k < G->vexnum; k++)
    {
    	if(G->vertex[k].data == v)	return k;
	}

    return (j);

}


void CreateList(AdjList *G) //用邻接表创建无向图

{

    int i;

    char v1, v2;

    printf("用邻接表来创建图\n请输入图的顶点个数和弧数\n");

    scanf("%d%d", &G->vexnum, &G->arcnum);

    printf("请用一行输入图的各个顶点,不用逗号隔开\n");

    getchar();

    for (i = 0; i < G->vexnum; i++)
    {

        scanf("%c", &G->vertex[i].data); //输入图的各个顶点

        G->vertex[i].firstarc = NULL;

    }

    printf("请用一行输入图中所有两顶点之间的弧,例如,a,b b,c b,d\n");

    int a1, a2;

    for (i = 0; i < G->arcnum; i++)
    {

        getchar();

        scanf("%c,%c", &v1, &v2);

        a1 = LocateVertex(G, v1);
        a2 = LocateVertex(G, v2);
        if(a1 == -1 || a2 == -1)	return ;
        
        Node* p1 = (Node*)malloc(sizeof(Node));
        p1->adjvex = a2;
        p1->nextarc = G->vertex[a1].firstarc;
        G->vertex[a1].firstarc = p1;
        
        Node* p2 = (Node*)malloc(sizeof(Node));
		p2->adjvex = a1;
		p2->nextarc = G->vertex[a2].firstarc;
		G->vertex[a2].firstarc = p2; 

    }
}


void print(AdjList *G)  //打印邻接表建立的图

{

    int i;

    printf("打印出用邻接表创建的无向图\n");

    for (i = 0; i < G->vexnum; i++)
    {

        printf("%c---->", G->vertex[i].data);

        Node *t;

        t = G->vertex[i].firstarc;

        while (t != NULL)
        {

            printf(" %c ", G->vertex[t->adjvex].data);

            t = t->nextarc;

        }

        printf("\n");

    }

}


void DFS(AdjList *g, int i)
{//单个节点开始进行深度优先遍历

    Node *t;

    printf("%c", g->vertex[i].data);

    visisted[i] = 1;

    t = g->vertex[i].firstarc;

    while (t)
    {

        int w = t->adjvex;
        if(!visisted[w])
        	DFS(g, w);
        t = t->nextarc;

    }

}



void BFS(AdjList *g, int i)
{
    int q[max_vertex_num]; // 用于模拟访问过结点的队列
    int front = 0, rear = 0; // front为队列的头部,rear为队列的尾部

    printf("%c", g->vertex[i].data);
    visisted1[i] = 1;
    q[rear++] = i; // 模拟入队

    Node *p;

    while (rear > front)
    {
        int temp = q[front++]; // 模拟出队
        p = g->vertex[temp].firstarc;

        while (p != NULL)
        {
            int neighbor = p->adjvex;
            if (!visisted1[neighbor])
            {
                printf("%c", g->vertex[neighbor].data);
                visisted1[neighbor] = 1;
                q[rear++] = neighbor; // 模拟入队
            }
            p = p->nextarc;
        }
    }
}


int main()
{

    AdjList GG;

    CreateList(&GG);

    print(&GG);

    printf("以A开始的深度优先遍历(DFS):\n");

    DFS(&GG, 0);

    printf("\n以A开始的广度优先遍历(BFS):\n");

    BFS(&GG, 0);

    printf("\n");

    return 0;

}
2. 图的基本操作–基于邻接矩阵建立图
#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX_NUM 100 // 最多顶点个数
#define OK 1
#define ERROR -1

typedef char VertexData;
typedef int AdjType;
typedef int OtherInfo;

typedef struct 
{
    AdjType adj; // 对于无权图,用1表示相邻,0表示不相邻;对于带权图,则为权值类型
    OtherInfo info;
} ArcNode;

typedef struct 
{
    VertexData vertex[MAX_VERTEX_NUM]; // 存储顶点的数组
    ArcNode arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
    int vexnum, arcnum; // 顶点的个数和边的个数
} AdjMatrix; // 邻接矩阵的结构体

int LocateVertex(AdjMatrix *G, VertexData v) 
{
    // 求顶点的位置
    for (int k = 0; k < G->vexnum; k++) 
    {
        if (G->vertex[k] == v) return k;
    }
    return -1; // 未找到顶点返回-1
}

void CreateMatrix(AdjMatrix *G) 
{
    // 用邻接矩阵创建无向图
    int i, j, k;
    char v1, v2;

    printf("用邻接矩阵来创建图\n请输入图的顶点个数和弧数\n");
    scanf("%d%d", &G->vexnum, &G->arcnum);

    // 初始化邻接矩阵
    for (i = 0; i < G->vexnum; i++) 
    {
        for (j = 0; j < G->vexnum; j++) 
        {
            G->arcs[i][j].adj = 0;
        }
        
    }

    printf("请用一行输入图的各个顶点,不用逗号隔开\n");
    getchar(); // 清除缓冲区中的换行符
    for (i = 0; i < G->vexnum; i++) 
    {
        scanf("%c", &G->vertex[i]);
    }

    printf("请用一行输入图中所有两顶点之间的弧,例如,a,b b,c b,d\n");
    for (k = 0; k < G->arcnum; k++) 
    {
        getchar(); // 清除缓冲区中的换行符
        scanf("%c,%c", &v1, &v2);

        int a1 = LocateVertex(G, v1);
        int a2 = LocateVertex(G, v2);

        if (a1 == -1 || a2 == -1) 
        {
            printf("顶点不存在.\n");
            return;
        }

        G->arcs[a1][a2].adj = 1;
        G->arcs[a2][a1].adj = 1;
    }
}

void PrintMatrix(AdjMatrix *G) 
{
    // 打印邻接矩阵建立的图
    printf("打印出用邻接矩阵创建的无向图\n");
    for (int i = 0; i < G->vexnum; i++) 
    {
        for (int j = 0; j < G->vexnum; j++) 
        {
            printf("%d ", G->arcs[i][j].adj);
        }
        printf("\n");
    }
}

int main() 
{
    AdjMatrix G;

    CreateMatrix(&G);
    PrintMatrix(&G);

    return 0;
}

3. 图的基本操作–基于邻接表建立图
#include <stdio.h>
#include <stdlib.h>

#define max_vertex_num 100 //最多顶点个数

typedef char VertexData;

typedef struct Node 
{
    int adjvex;  //定义该弧指向顶点的位置
    struct Node *nextarc; //定义下一条弧上网指针
} Node;

typedef struct 
{
    VertexData data; //定义顶点的数据
    Node *firstarc;  //定义该顶点第一条弧的指针
} VertexNode;

typedef struct 
{
    VertexNode vertex[max_vertex_num];
    int vexnum, arcnum;
} AdjList;  //定义邻接表

int LocateVertex(AdjList *G, VertexData v)  //求顶点的位置
{
    for (int k = 0; k < G->vexnum; k++) {
        if (G->vertex[k].data == v) return k; 
    }
    return -1;
}

void CreateList(AdjList *G) //用邻接表创建无向图
{
    int i;
    char v1, v2;

    printf("用邻接表来创建图\n请输入图的顶点个数和弧数\n");
    scanf("%d%d", &G->vexnum, &G->arcnum);

    printf("请用一行输入图的各个顶点,不用逗号隔开\n");
    getchar(); // Consume the newline character left by previous input

    for (i = 0; i < G->vexnum; i++) 
    {
        scanf("%c", &G->vertex[i].data); //输入图的各个顶点
        G->vertex[i].firstarc = NULL;
    }

    printf("请用一行输入图中所有两顶点之间的弧,例如,a,b b,c b,d\n");

    for (i = 0; i < G->arcnum; i++) 
    {
        getchar(); // Consume the newline character left by previous input
        scanf("%c,%c", &v1, &v2);

        int a1 = LocateVertex(G, v1);
        int a2 = LocateVertex(G, v2);

        if (a1 == -1 || a2 == -1) 
        {
            printf("顶点未找到\n");
            return;
        }

        // Create first node and link it to the first arc of a1
        Node *p1 = (Node *)malloc(sizeof(Node));
        p1->adjvex = a2;
        p1->nextarc = G->vertex[a1].firstarc;
        G->vertex[a1].firstarc = p1;

        // Create second node and link it to the first arc of a2 (since the graph is undirected)
        Node *p2 = (Node *)malloc(sizeof(Node));
        p2->adjvex = a1;
        p2->nextarc = G->vertex[a2].firstarc;
        G->vertex[a2].firstarc = p2;
    }
}

void print(AdjList *G)  //打印邻接表建立的图
{
    printf("打印出用邻接表创建的无向图\n");

    for (int i = 0; i < G->vexnum; i++) 
    {
        printf("%c---->", G->vertex[i].data);

        Node *t = G->vertex[i].firstarc;
        while (t != NULL) 
        {
            printf(" %c ", G->vertex[t->adjvex].data);
            t = t->nextarc;
        }
        printf("\n");
    }
}

int main()
{
    AdjList GG;

    CreateList(&GG);
    print(&GG);

    return 0;
}

4. 社交网络下的谣言传播分析(1)
#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX_NUM 20  // 最大顶点数

typedef struct ArcNode {
    int adjvex;  // 该边所连接的顶点的位置(即该顶点的数组下标)
    struct ArcNode *nextarc;  // 指向下一条边的指针
    int info;  // 边的权值
} ArcNode;

typedef struct VNode {
    int data;  // 顶点信息
    ArcNode *firstarc;  // 指向第一条依附该顶点的边的指针
} VNode, AdjList[MAX_VERTEX_NUM];

typedef struct ALGraph {
    AdjList vertices;
    int vexnum, arcnum;  // 图的当前顶点数和弧数
} ALGraph;

// 建立关系网的邻接表数据存储结构
void CreateUDN(ALGraph *G) {
    scanf("%d %d", &G->vexnum, &G->arcnum);
    
    // 初始化顶点表
    for (int i = 1; i <= G->vexnum; i++) {
        G->vertices[i].data = i;
        G->vertices[i].firstarc = NULL;
    }
    
    // 构建边表
    for (int i = 0; i < G->arcnum; i++) {
        int a1, a2, w;
        scanf("%d %d %d", &a1, &a2, &w);
        
        // 插入边 a1 -> a2
        ArcNode *p1 = (ArcNode*)malloc(sizeof(ArcNode));
        p1->adjvex = a2;
        p1->info = w;
        p1->nextarc = G->vertices[a1].firstarc;
        G->vertices[a1].firstarc = p1;
        
        // 插入边 a2 -> a1
        ArcNode *p2 = (ArcNode*)malloc(sizeof(ArcNode));
        p2->adjvex = a1;
        p2->info = w;
        p2->nextarc = G->vertices[a2].firstarc;
        G->vertices[a2].firstarc = p2;
    }
}

// 统计顶点的边的权值之和
int VexCount(ALGraph G, int v) 
{
    int sum = 0;
    ArcNode *p = G.vertices[v].firstarc;
    while (p != NULL) 
    {
        sum += p->info;
        p = p->nextarc;
    }
    return sum;
}

int main() 
{
    ALGraph G;
    CreateUDN(&G);

    for (int i = 0; i < G.vexnum; i++) 
    {
        printf("%d ", VexCount(G, i + 1));
    }
    printf("\n");
    return 0;
}

5. 求最小生成树的权值之和
#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX_NUM 100
#define INFINITY 99999

typedef struct {
    int u, v; // 边的两个顶点
    int weight; // 边的权值
} Edge;

typedef struct {
    int vexnum; // 顶点数量
    int edgenum; // 边数量
    Edge edges[MAX_VERTEX_NUM * (MAX_VERTEX_NUM - 1) / 2]; // 边集数组
} Graph;

int parent[MAX_VERTEX_NUM]; // 并查集的父节点数组

// 并查集查找根节点
int find(int x) {
    if (parent[x] != x) {
        parent[x] = find(parent[x]); // 路径压缩
    }
    return parent[x];
}

// 并查集合并
void unionSet(int x, int y) {
    int rootX = find(x);
    int rootY = find(y);
    if (rootX != rootY) {
        parent[rootX] = rootY;
    }
}

// 边的比较函数,用于qsort排序
int compareEdges(const void *a, const void *b) {
    return ((Edge *)a)->weight - ((Edge *)b)->weight;
}

// Kruskal算法求最小生成树的权值
int kruskalMST(Graph *G) 
{
    int totalWeight = 0, i;
    int edgeCount = 0;

    // 初始化并查集
    for (i = 1; i <= G->vexnum; i++) {
        parent[i] = i;
    }

    // 按权值升序排序所有边
    qsort(G->edges, G->edgenum, sizeof(Edge), compareEdges);

    // 选择边加入最小生成树
    for (i = 0; i < G->edgenum; i++) {
        int u = G->edges[i].u;
        int v = G->edges[i].v;
        int weight = G->edges[i].weight;

        // 如果加入这条边不会形成环
        if (find(u) != find(v)) 
        {
            unionSet(u, v);
            totalWeight += weight;
            edgeCount++;
            // 如果边数达到了顶点数-1,说明最小生成树构建完成
            if (edgeCount == G->vexnum - 1) 
            {
                break;
            }
        }
    }

    return totalWeight;
}

int main() 
{
    Graph G;
    int n, count, i;

    // 输入顶点数和边数
    scanf("%d %d", &n, &count);
    G.vexnum = n;
    G.edgenum = count;

    // 输入每条边
    for (i = 0; i < count; i++) 
    {
        int u, v, weight;
        scanf("%d %d %d", &u, &v, &weight);
        G.edges[i].u = u;
        G.edges[i].v = v;
        G.edges[i].weight = weight;
    }

    // 计算并输出最小生成树的权值
    int result = kruskalMST(&G);
    printf("%d\n", result);

    return 0;
}
6. 动态规划模拟测试题
//AI大牛 C语言版
#include <stdio.h>
#include <limits.h>

#define VERTEX_NUM 12  // 顶点数量
#define MAX_EDGES 21   // 最大边数量

// 结构体定义边
struct Edge {
    int from, to, weight;
};

// 给定的边及权重
struct Edge edges[MAX_EDGES] = {
    {1, 2, 9}, {1, 3, 7}, {1, 4, 3}, {1, 5, 2},
    {2, 6, 4}, {2, 7, 2}, {2, 8, 1}, {3, 6, 2}, {3, 7, 7},
    {4, 8, 11}, {5, 7, 11}, {5, 8, 8}, {6, 9, 6}, {6, 10, 5},
    {7, 9, 4}, {7, 10, 3}, {8, 10, 5}, {8, 11, 6}, {9, 12, 4},
    {10, 12, 2}, {11, 12, 5}
};

int main() {
    int stages;
    scanf("%d", &stages);

    int stage_nodes[stages][VERTEX_NUM];
    int stage_sizes[stages];  // 每个阶段的节点数量

    for (int i = 0; i < stages; ++i) {
        int node;
        stage_sizes[i] = 0;
        while (scanf("%d", &node) == 1) {
            stage_nodes[i][stage_sizes[i]++] = node;
            if (getchar() == '\n') break;
        }
    }

    int dist[VERTEX_NUM + 1];
    int path[VERTEX_NUM + 1];

    for (int i = 0; i <= VERTEX_NUM; ++i) {
        dist[i] = INT_MAX;
        path[i] = -1;
    }

    dist[1] = 0;  // 源点到自己的距离为0

    for (int i = 0; i < stages - 1; ++i) {
        for (int j = 0; j < stage_sizes[i]; ++j) {
            int u = stage_nodes[i][j];
            for (int k = 0; k < MAX_EDGES; ++k) {
                if (edges[k].from == u) {
                    int v = edges[k].to;
                    if (dist[u] != INT_MAX && dist[u] + edges[k].weight < dist[v]) {
                        dist[v] = dist[u] + edges[k].weight;
                        path[v] = u;
                    }
                }
            }
        }
    }

    int target = 12;
    printf("%d\n", dist[target]);

    int shortest_path[VERTEX_NUM];
    int shortest_path_length = 0;

    for (int v = target; v != -1; v = path[v]) {
        shortest_path[shortest_path_length++] = v;
    }

    for (int i = shortest_path_length - 1; i >= 0; --i) {
        printf("%d ", shortest_path[i]);
    }
    printf("\n");

    return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值