博客作业—图
1.学习总结
1.1图的思维导图
1.2 图结构学习体会
谈谈你对图结构中的几个经典算法学习体会。具体有:
- 深度遍历算法和广度遍历算法:理解起来相对容易,尤其是在邻接矩阵中,找起来很方便,重要的就是要细心,做到不重不漏
- Prim和Kruscal算法:prim算法把顶点分成已选和未选的思路很好,但相比来说kruscal算法找最小边更为精确,代码量也小
- Dijkstra算法:时间复杂度为O(n²),要很认真地去观察新添顶点后,点与点之间的距离能不能更小
- 拓扑排序算法:一定要有向图,要去判断有没有环路,有环路则为错误
2.PTA实验作业
1.1 题目1:7-1 图着色问题
1.2 设计思路
图着色问题是一个著名的NP完全问题。给定无向图,,问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?
但本题并不是要我们解决这个着色问题,而是对给定的一种颜色分配,判断这是否是图着色问题的一个解。
重点代码流程为:使用回溯法将visited数组初始化为0-->依次观察每一种颜色,若顶点之间的着色不冲突则转下一步骤,否则继续搜索-->若顶点全部着色,输出数组
-->若顶点是一个合法着色,则转处理下一个-->否则重置顶点颜色
1.3 代码截图
1.4 PTA提交列表说明
说明:主要是细节处理问题,自己应该清楚每个循环结构体开始和结束的地方!!!
2.1 题目2:7-2 排座位
2.2 设计思路
题目关于敌对和朋友问题说的很拗口,但简化起来:关系
为1表示是朋友,-1表示是死对头--->朋友两顶点的权值为1,死对头两顶点权值为-1;
如果两位宾客之间是朋友,且没有敌对关系,则输出No problem
;如果他们之间并不是朋友,但也不敌对,则输出OK
;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...
;如果他们之间只有敌对关系,则输出No way
。---->权值为1,No problem;没有连接,OK;有共同根,OK but...;权值为-1,No way。代码主要就是建图和判断两点关系。
2.3 代码截图
2.4 PTA提交列表说明
说明:没注意看清输出要求里面大小写和点,以后要认真审题!!!
3.1 题目3:7-5 畅通工程之最低成本建设问题
3.2 设计思路
成本问题就是最短路径问题,用最小生成树来求解问题,由输入数据建立带权的无向图,判断两顶点(两城镇)的
最短路径(最低成本建设)。
3.3 代码截图
3.4 PTA提交列表说明
说明:对Prim算法的熟练度不够,改动课本源代码比较慢。
3.截图本周题目集的PTA最后排名
4. 阅读代码
六度空间是一个看似复杂的大数据结构,但经过图结构的简化,将人与人的关系建立起来,
更好地判断他们的关系,足以见得图结构的优势
- #include<stdio.h>
- #include<malloc.h>
- #define MAX 10001//最大顶点数
- /**
- *解题思想:
- *对图进行广度搜索
- *得出每层中的顶点数
- *计算百分比
- */
- int BFS(int i, int N, int ** snap)
- {// 队列 遍历登记 队头 队尾 计数器 层数
- int q[MAX], visit[MAX], front, rear, count, level, last, tail, v, j;
- for (j = 0; j < 10001; j++)//初始化数组
- visit[j] = 0;
- visit[i] = 1;//开始结点
- front = rear = -1;//队列初始化
- count = 1;//计算六度空间的个数
- level = 0;//level计算层数,等于6时跳出
- last = i;//last为上一层最后的顶点
- q[++rear] = i;//入队 当前顶点所在层数
- while (front<rear) //遍历队列(六层以内)
- {
- /*
- *图的广度搜索原理解析:
- *类似二叉树的层序遍历
- *1、从所需要的顶点进入图(类似利用此顶点为树的根结点,构建一棵树)
- *2、根结点入队列
- *3、寻找与此顶点相连的所有顶点并放入队列中(图的临接矩阵中,储存的是每个顶点间的边的关系,而且无向图的临接矩阵一定为对称矩阵)
- *4、当顶点所在行遍历结束,取出队列的下一个顶点,重复。直至遍历所有的顶点
- */
- v = q[++front]; //出队
- for (j = 1; j <= N; j++)//遍历
- if (!visit[j] && snap[v][j] == 1)
- {//当结点没有记录而且此处结点为顶点时
- q[++rear] = j;//入队列
- visit[j] = 1;//记录对应位置
- count++;//计数器
- tail = j;//tail是当前层的最后一个顶点
- }
- if (v == last)
- {
- level++;//层数加一
- last = tail;//记录最后一个顶点
- }
- if (6 == level)//等于六层时,退出循环
- break;
- }
- return count;//返回六度空间内所有顶点数
- }
- int main(void)
- {
- int N, M;
- int count = 0;
- scanf("%d %d", &N, &M);
- int **snap;//实现动态分配二维数组
- /*注意:
- *******动态分配必须按照顺序分配
- *******同时数组释放内存的时候要按照先后顺序释放
- *******否则会出现野指针
- *******内存泄漏导致程序崩溃
- */
- snap = (int**)malloc(sizeof(int*) * (N + 1));
- if (snap == NULL)
- return -1;
- //动态分配内存存在失败的可能,所以
- //在进行动态分配内存后
- //应该进行对应的指针是否为空指针的判断
- int i, x, y, j;
- for (i = 0; i <= N; i++)
- {
- *(snap + i) = (int *)malloc(sizeof(int) * (N + 1));
- if (*(snap + i) == NULL)
- return -1;
- }
- for (i = 0; i < M; i++)
- {
- scanf("%d %d", &x, &y);//无向图对角线对称
- snap[x][y] = snap[y][x] = 1;//关系对等
- }
- for (i = 1; i <= N; i++)
- {
- count = BFS(i, N, snap);
- printf("%d: %.2f%%\n", i, (float)count / N * 100);
- }
- //直接进行头指针的内存释放不全等于所有指针内存的释放
- //free(snap);
- for (i = 0; i < N; i++)
- {
- free(*(snap + i));
- *(snap + i) = NULL;
- }
- free(snap);
- snap = NULL;
- return 0;
- }