大一下数据结构编程实验——图形结构及其应用

题目一:社交网络下谣言传播分析

题目简述:
社交网络化的时代,谣言的传播顺延着关系网的飞速传播着。
假设现在有N个节点,标记为1到N。给定一个列表 times,表示一个谣言经过有向边的传递时间。 times[i] = (u, v, w),其中 u 是源节点,v 是目标节点, w 是一个谣言从源节点传递到目标节点的时间(非负数)。
假设当前节点K产生了一个谣言。请你来分析最少需要多少时间,整个网络将会充斥这个谣言(假设现阶段没有任何辟谣行为,网络内所有节点都想沿着有向边传播信息)。

输入格式:
第一行包含三个整数𝑁 𝑀 𝑆,分别表示点的个数、有向边的个数、出发节点的编号。
接下来𝑀行每行包含三个整数U_𝑖 V_𝑖 𝑊_𝑖,分别表示第𝑖条有向边的出发点、目标点和传播时间

输出格式:
整数,代表最小传播时间。消息无法传播整个网络时返回-1

输入样例:
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出样例:
4

在这里插入图片描述

题目二:初识神经网络

题目简述:
神经网络是一门重要的机器学习技术。它是目前最为火热的研究方向——深度学习的基础。学习神经网络不仅可以让你掌握一门强大的机器学习方法,同时也可以更好地帮助你理解深度学习技术。
在这里插入图片描述
为了简单起见,在这里我们将神经网络简化成一个有向无环图𝐺(𝑉,𝐸)模型,图的节点称为神经元。神经网络分为三层:输入层、隐藏层和输出层。输入层的神经元没有有向边连入,输出层的神经元没有有向边连出,其余神经元都属于隐藏层。神经元与神经元之间通过有向边连接,连接神经元𝑣_𝑖和神经元𝑣_𝑗的有向边上带有系数𝑊_𝑖𝑗。向每个输入层神经元输入一个初始权值𝐶_𝑖=𝑋_𝑖 ,则其他神经元的权值通过以下公式计算:
𝐶_𝑖=∑1_(<𝑖,𝑗>∈𝐸)▒〖𝑊_𝑖𝑗 𝐶〗_𝑗
即每个神经元的权值等于所有有边指向它的神经元权值乘指向它的边系数的加和。最终,输出层神经元的输出等于输出层神经元的权值𝑌=𝐶_𝑛。
我们把上述过程叫做正向传播。

现在,以邻接矩阵的形式给出神经网络的结构,并给出每个输入层神经元的输入,请完成正向传播算法,求出每个输出层神经元输出的权值𝑌_𝑖。

输入格式:
第一行包含四个正整数𝑁 𝑀 𝑃 𝑄,表示总神经元个数,总的边个数,输入层神经元个数以及输出层神经元个数。
接下来𝑀行,每三个正整数𝑖 𝑗 𝑤_𝑖𝑗,表示有一条从𝑖号神经元指向𝑗号神经元的有向边,边权为𝑤_𝑖𝑗。
接下来一行𝑃个正整数,表示每个输入层神经元的输入值。
注:1到𝑃号节点为输入层神经元,𝑃+1到𝑁−𝑄号节点为隐藏层神经元,𝑁−𝑄+1到𝑁号节点为输出层神经元。

输出格式:
输出一行包含𝑄个整数,表示每个输出层神经元的输出值。

样例输入:
8 10 2 1
1 3 2
1 4 1
2 4 3
2 5 3
3 6 4
4 6 2
4 7 2
5 7 7
6 8 2
7 8 1
5 10

样例输出:
500

在这里插入图片描述

简要解析

第一题考察的主要知识点就是从某个顶点出发到其余各个顶点的最短路径,把所有最短路径求出来后,取其最大值即可。值得注意的是,如果最大值为无穷大,那么该消息无法在社区范围内完全传播。

第二题只需要按顺序求出每个顶点的所有前驱点与所有入射弧的权值的乘积之和即可。

求解代码

//题目一
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INFINITY 65535  //无穷大
#define MAX_VERTEX_NUM 20  //最大顶点数

//矩阵弧
typedef struct ArcCell
{
    unsigned int weight;  //权值
}AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

//矩阵图
typedef struct MGraph
{
    AdjMatrix arcs;  //邻接矩阵
    int vexnum, arcnum;  //顶点数,弧数
}MGraph;

//手动建立关系网
int Manual_CreatN(MGraph *G)
{
    int i, j;
    int V1, V2, Start_Node, Weight;
    while(getchar() != '\n')continue;
    printf("\nInput the number of vex(<20),arc,start_node: ");
    while(scanf("%d%d%d", &G->vexnum, &G->arcnum, &Start_Node) != 3)  //顶点数,弧数,原点
    {
        while(getchar() != '\n')continue;
        printf("Error!Input again: ");
    }
    for(i = 0; i < G->vexnum; i++)
    {
        for(j = 0; j < G->vexnum; j++)
        {
            G->arcs[i][j].weight = INFINITY;  //初始化邻接矩阵,无通路时的代价为无穷大
        }
    }
    for(i = 0; i < G->arcnum; i++)
    {
        while(getchar() != '\n')continue;
        printf("Input V1,V2(V1->V2),Weight: ");
        while(scanf("%d%d%d", &V1, &V2, &Weight) != 3)
        {
            while(getchar() != '\n')continue;
            printf("Error!Input again: ");
        }
        G->arcs[V1-1][V2-1].weight = Weight;  //更新矩阵相应位置的值
    }
    return (Start_Node-1);  //原点位置等于原点序号-1
}

//计算并返回最小时间
//最小时间即从原点到其余所有顶点最短路径的最大权值
int Get_min_time(MGraph G, int Start_Node)
{
    int i, v, w, Min, Min_time = -1;
    int D[G.vexnum], Final[G.vexnum];  //最短路径带权长度,最短路径求解状态
    for(v = 0; v < G.vexnum; v++)
    {
        Final[v] = 0;  //未求得最短路径
        D[v] = G.arcs[Start_Node][v].weight;  //初始化为各顶点与原点的权值
    }
    D[Start_Node] = 0;
    Final[Start_Node] = 1;
    for(i = 1; i < G.vexnum; i++)
    {
        Min = INFINITY;  //当前离原点最近权值
        for(w = 0; w < G.vexnum; w++)
        {
            if(!Final[w])
            {
                if(D[w] < Min)  //w离原点更近
                {
                    v = w;
                    Min = D[w];
                }
            }
        }
        Final[v] = 1;
        for(w = 0; w < G.vexnum; w++)  //更新当前最短路径及权值
        {
            if(!Final[w] && (Min + G.arcs[v][w].weight < D[w]))  //更新各顶点与原点的权值
            {
                D[w] = Min + G.arcs[v][w].weight;
            }
        }
    }
    for(i = 0; i < G.vexnum; i++)
    {
        if(i == Start_Node)continue;  //原点
        if(D[i] == INFINITY)return -1;  //存在权值为无穷大的顶点,消息不能完全传播
        Min_time = D[i] > Min_time? D[i] : Min_time;  //将最小时间赋值为最大权值
    }
    return Min_time;
}

//手动输入方式
void Manual_Way(MGraph *G, int count)
{
    int Min_time, Start_Node;
    Start_Node = Manual_CreatN(G);  //建图
    Min_time = Get_min_time(*G, Start_Node);  //求解最小时间
    printf("\nNo.%02d Min_time: %d\n", count, Min_time);
}

//文件输入方式
void File_Way(MGraph *G, int count)
{
    int i, j, V1, V2, Weight, Start_Node, Min_time;
    freopen("4_1_input.in", "r", stdin);
    printf("\nHere are the results of all the questions in the document \"4_1_input.in\".\n");
    while (scanf("%d%d%d", &G->vexnum, &G->arcnum, &Start_Node) != EOF)  //顶点数,弧数,原点
    {
        count++;
        for(i = 0; i < G->vexnum; i++)
        {
            for(j = 0; j < G->vexnum; j++)
            {
                G->arcs[i][j].weight = INFINITY;  //初始化邻接矩阵,无通路时的代价为无穷大
            }
        }
        for(i = 0; i < G->arcnum; i++)
        {
            if(scanf("%d%d%d", &V1, &V2, &Weight) != EOF)
                G->arcs[V1-1][V2-1].weight = Weight;  //更新矩阵相应位置的值
            else
            {
                printf("\nThe rest of data is not enough to build a diagram! Please check the data in the file.\n");
                exit(0);
            }
        }
        Min_time = Get_min_time(*G, Start_Node-1);
        printf("\nNo.%02d Min_time: %d\n", count, Min_time);
    }
    fclose(stdin);
}

int main()
{
    MGraph MG;
    int choice;
    static int count = 0;
    char order;
    printf("1.Manual input  2.File input  else.Quit\n");
    printf("Which way do you want to input data?  ");  //选择输入数据的方式
    scanf("%d", &choice);
    switch (choice)
    {
        case 1: do{
                count++;
                Manual_Way(&MG, count);
                while(getchar() != '\n')continue;
                printf("\nDo you want to do it again(Y(y)/N(n))?  ");
                scanf("%c", &order);
                }while(order == 'Y' || order == 'y');
                break;
        case 2: File_Way(&MG, count);
                break;
        default:exit(0);
    }
    return 0;
}

//题目二
#include <stdio.h>
#include <stdlib.h>
#define INFINITY 65535  //无穷大
#define MAX_VERTEX_NUM 30  //最大顶点数

//链图弧
typedef struct ArcNode
{
    int position;  //该弧所指向的顶点的位置
    int weight;  //弧系数
    struct ArcNode *nextarc;  //指向下一条弧的指针
}ArcNode;

//链图顶点
typedef struct
{
    int data;  //顶点权值
    ArcNode *firstarc;  //指向第一条弧的指针
}AdjList[MAX_VERTEX_NUM];

//链表图
typedef struct
{
    AdjList vertices;
    int vexnum, arcnum;  //顶点数,弧数
}ALGraph;

//计算并打印所有输出神经元的权值
//顶点的权值等于所有以该顶点为尾的顶点的权值乘以弧的系数的和
void Forward_Propagation(ALGraph ALG, int Q)  //Q表示输出神经元的数量
{
    int i;
    ArcNode *p;
    for(i = 0; i < ALG.vexnum; i++)  //遍历链图
    {
        p = ALG.vertices[i].firstarc;
        while(p)
        {
            ALG.vertices[p->position].data += (p->weight * ALG.vertices[i].data);  //弧头顶点的权值等于其原有权值加上该弧的系数与弧为顶点的权值的乘积
            p = p->nextarc;
        }
    }
    for(i = (ALG.vexnum-Q); i < ALG.vexnum; i++)  //按顺序打印输出神经元的权值
    {
        printf("No.%02d Output_neuron: %d\n", (i-ALG.vexnum+Q+1), ALG.vertices[i].data);
    }
}

//手动建立链图并计算和打印所有输出神经元的权值
void Manual(ALGraph *ALG)
{
    int i, P, Q, V1, V2, Weight;
    ArcNode *p, *q;
    while(getchar() != '\n')continue;
    printf("\nInput N,M,P,Q: ");
    while(scanf("%d%d%d%d", &ALG->vexnum, &ALG->arcnum, &P, &Q) != 4)  //顶点数,弧数,输入神经元个数,输出神经元个数
    {
        while(getchar() != '\n')continue;
        printf("Error!Input again: ");
    }
    for(i = 0; i < ALG->vexnum; i++)  //初始化链图
    {
        ALG->vertices[i].data = 0;
        ALG->vertices[i].firstarc = NULL;
    }
    for(i = 0; i < ALG->arcnum; i++)
    {
        p = (ArcNode *)malloc(sizeof(ArcNode));  //分配空间
        while(getchar() != '\n')continue;
        printf("Input V1,V2(V1->V2),Weight: ");
        while(scanf("%d%d%d", &V1, &V2, &Weight) != 3)
        {
            while(getchar() != '\n')continue;
            printf("Error!Input again: ");
        }
        p->position = V2-1;  //弧头顶点的位置等于顶点序号-1
        p->weight = Weight;
        p->nextarc = NULL;  //指向下一条弧的指针初始化为NULL
        if(!ALG->vertices[V1-1].firstarc)  //该弧为第一条弧
            ALG->vertices[V1-1].firstarc = p;
        else
        {
            q = ALG->vertices[V1-1].firstarc;
            while(q->nextarc)
            {
                q = q->nextarc;
            }
            q->nextarc = p;  //插入链表末尾
        }
    }
    for(i = 0; i < P; i++)
    {
        while(getchar() != '\n')continue;
        printf("Input the data of the No.%02d Input_neuron: ", i+1);
        while(!scanf("%d", &ALG->vertices[i].data))  //输入神经元依次赋值
        {
            while(getchar() != '\n')continue;
            printf("Error!Input again: ");
        }
    }
    Forward_Propagation(*ALG, Q);  //计算并打印所有输出神经元的权值
}

//文件建立链图
void File(ALGraph *ALG)
{
    int i, P, Q, V1, V2, Weight, count = 0;
    ArcNode *p, *q;
    freopen("4_2_input.in", "r", stdin);  //打开文件
    printf("\nHere are the results of all the questions in the document \"4_2_input.in\".\n");
    while(scanf("%d%d%d%d", &ALG->vexnum, &ALG->arcnum, &P, &Q) != EOF)
    {
        count++;
        for(i = 0; i < ALG->vexnum; i++)  //初始化链图
        {
            ALG->vertices[i].data = 0;
            ALG->vertices[i].firstarc = NULL;
        }
        for(i = 0; i < ALG->arcnum; i++)
        {
            p = (ArcNode *)malloc(sizeof(ArcNode));  //分配空间
            if(scanf("%d%d%d", &V1, &V2, &Weight) != EOF)
            {
                p->position = V2-1;  //弧头顶点的位置等于顶点序号-1
                p->weight = Weight;
                p->nextarc = NULL;  //指向下一条弧的指针初始化为NULL
            }
            else
            {
                printf("The rest of data is not enough to build a diagram! Please check the data in the file.\n");
                exit(0);
            }
            if(!ALG->vertices[V1-1].firstarc)  //该弧为第一条弧
                ALG->vertices[V1-1].firstarc = p;
            else
            {
                q = ALG->vertices[V1-1].firstarc;
                while(q->nextarc)
                {
                    q = q->nextarc;
                }
                q->nextarc = p;  //插入链表末尾
            }
        }
        for(i = 0; i < P; i++)
        {
            scanf("%d", &ALG->vertices[i].data);  //输入神经元依次赋值
        }
        printf("Question %02d:\n", count);
        Forward_Propagation(*ALG, Q);  //计算并打印所有输出神经元的权值
        printf("\n");
    }
    fclose(stdin);  //关闭文件
}

int main()
{
    ALGraph ALG;
    int i, choice;
    char order;
    printf("1.Manual input  2.File input  else.Quit\n");
    printf("Which way do you want to input data?  ");  //选择输入数据的方式
    scanf("%d", &choice);
    switch (choice)
    {
        case 1: do{
                Manual(&ALG);
                while(getchar() != '\n')continue;
                printf("\nDo you want to do it again(Y(y)/N(n))?  ");
                scanf("%c", &order);
                }while(order == 'Y' || order == 'y');
                break;
        case 2: File(&ALG);
                break;
        default:exit(0);
    }
    return 0;
}

在这里插入图片描述

链式向前星介绍

输入边的顺序为:
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

示意图:
在这里插入图片描述

邻接矩阵:
在这里插入图片描述

邻接表:
在这里插入图片描述

链式向前星:
前向星是一种特殊的边集数组。
head[i]:以节点i为起点的边集在edge数组中的第一个存储位置.
edge[j]:第i条边的边集

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

敲黑板!!!图形结构是数据结构中比较难但也非常重要的一大部分,有必要为其提供特殊服务哦!!!(yysy, 我都还不会,呜呜呜。。。)

凉梦空间

欢迎你进入我的个人博客网站参观交流:https://www.liangmeng.xyz

在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉丶梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值