列出连通集
题目
给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式:
按照 ${v_1, v_2, ···, v_k}$ 的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。
输入样例:
8 6
0 7
0 1
2 0
4 1
2 4
3 5
输出样例:
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
实现代码
#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;
#define MAX 10
int a[MAX][MAX], dfs_visited[MAX], bfs_visited[MAX], N, E; //dfs_visited数组表示dfs
queue<int> q;
void dfs(int c){
dfs_visited[c] = 1; //1表示访问过了
printf(" %d", c);
for(int i = 0; i < N; i++)
if(a[c][i] && !dfs_visited[i]) //利用二维数组的一行就是该节点的邻接点,如果那个邻接点还没没访问过则递归访问
dfs(i);
}
void bfs(int c){
bfs_visited[c] = 1; //1表示访问过了
q.push(c);
printf(" %d", c);
while(!q.empty()){ //如果队列不空则每次从队列中取出一个节点找出该节点的第一层bfs节点,并加入队列中
int temp = q.front();
q.pop();
for(int i = 0; i < N; i++){ //找出第一层bfs的节点,依次输出并加入队列,跟树的层次遍历很像
if(a[temp][i] && !bfs_visited[i]){
printf(" %d", i);
bfs_visited[i] = 1;
q.push(i);
}
}
}
}
int main(){
int temp1, temp2;
scanf("%d%d", &N, &E);
for(int i = 0; i < E; i++){
scanf("%d%d", &temp1, &temp2);
a[temp1][temp2] = 1; //因为是无向图所有邻接矩阵是关于主对角线对称的
a[temp2][temp1] = 1;
}
for(int i = 0; i < N; i++){
if(!dfs_visited[i]){
putchar('{');
dfs(i);
printf(" }\n");
}
}
for(int i = 0; i < N; i++){
if(!bfs_visited[i]){
putchar('{');
bfs(i);
printf(" }\n");
}
}
return 0;
}
提交结果
哈利·波特的考试
题目
哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。
现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。
输入格式:
输入说明:输入第1行给出两个正整数N (≤100)和M,其中N是考试涉及的动物总数,M是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N编号。随后M行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100),数字之间用空格分隔。
输出格式:
输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。
输入样例:
6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80
输出样例:
4 70
解读题目
本题可以视为一个无向带权图,题目里以字符长度来衡量难度,因此带鼠去,无论是变猫还是变鱼,都只需要4个字符。在输入样例中,第一行的6代表动物个数,即图里面顶点的个数,11表示边的个数,接下来的每一行给出两个顶点和它们之间的权重,这些数据对应一张无向的网图。
本题的目的在于找出任意两个顶点之间的最短路径,用 FLoyd 算法。将图用邻接矩阵表示后,对每一个顶点扫描它到其它顶点的最大值, 记录下来,再在这些最大值里找一个最小值,即我们想要得到的那个顶点。在本题中,也就是哈利应该带该点所对应的动物去。这样,我们就成功的帮哈利完成了考试该带什么去的难题!
程序框架如下:
int main()
{
Graph G = BuildGraph(); //读入图
FindAnimal(G); //分析图
return 0;
}
实现代码
#include<iostream>
#include<fstream>
using namespace std;
//ifstream InFile("C:\\Users\\DELL\\Desktop\\in.txt",ios::in);
#define MaxVertexNum 200 //最大顶点数设为100
#define INFINITY1 65535 //∞设为双字节无符号整数的最大值65535
typedef int Vertex; //用顶点下标表示顶点,为整形
typedef int WeightType; //边的权值设为整形
typedef char DataType; //顶点储存的数据类型设为字符型
//图结点的定义
typedef struct GNode* PtrToGNode;
struct GNode{
int Nv; //顶点数
int Ne; //边数
WeightType G[MaxVertexNum][MaxVertexNum]; //邻接矩阵
DataType Data[MaxVertexNum]; //存顶点的数据
//注意:若顶点无数据,此时Data[]可以不出现
};
typedef PtrToGNode MGraph;
//边的定义
typedef struct ENode* PtrToENode;
struct ENode{
Vertex V1,V2; //无向边(v1,v2)
WeightType Weight; //权重
};
typedef PtrToENode Edge;
MGraph CreateGraph(int VertexNum)
{
MGraph Graph = new GNode;
Graph->Nv = VertexNum;
Graph->Ne = 0;
for(int i=0;i<Graph->Nv+2 ;++i){
for(int j=0;j<Graph->Nv+2 ;++j){
Graph->G[i][j] = INFINITY1;
}
}
return Graph;
}
void InsertEdge(MGraph Graph,Edge E)
{
Graph->G[E->V1][E->V2] = E->Weight;
Graph->G[E->V2][E->V1] = E->Weight;
}
MGraph BulidGraph()
{
Vertex N,M;
cin >> N>>M;
Edge E=new ENode;
MGraph Graph = CreateGraph(N);
if(Graph->Nv >0){
for(int i=0;i<M;++i){
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(Graph, E);
}
}
return Graph;
}
//Floyd
bool Floyd(MGraph Graph,WeightType D[][MaxVertexNum])
{
for(int i=0;i<Graph->Nv +2;++i){
for(int j=0;j<Graph->Nv +2;++j){
D[i][j] = Graph->G[i][j];
}
}
for(int k=1;k<=Graph->Nv ;++k){
for(int i=0;i<=Graph->Nv ;++i){
for(int j=0;j<=Graph->Nv ;++j){
if(i!=j&&D[i][k]+D[k][j]<D[i][j]){
D[i][j] = D[i][k] + D[k][j];
if (i == j&&D[i][j]<0) {
return false;
}
}
}
}
}
return true;
}
void FindAnimal(MGraph Graph)
{
WeightType D[MaxVertexNum][MaxVertexNum];
WeightType Max[MaxVertexNum];
Floyd(Graph, D);
for(int i=1;i<=Graph->Nv ;++i){
int m = -1;
for(int j=1;j<=Graph->Nv ;++j){
if(i!=j&&m<D[i][j]){
m = D[i][j];
}
if(i!=j&&D[i][j]==INFINITY1){
cout << 0 << endl;
return;
}
}
Max[i] = m;
}
int ret = 1;
for(int i = 2; i <= Graph->Nv; ++i){
//cout << Max[i] << endl;
if(Max[ret]>Max[i]){
ret = i;
}
}
cout << ret << " " << Max[ret] << endl;
}
int main()
{
MGraph Graph = BulidGraph();
FindAnimal(Graph);
delete Graph;
//InFile.close();
system("pause");
return 0;
}
提交结果
旅游规划
题目
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。
输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
3 40
题目解读
这是一个图论里单源最短路径问题,我们用 Dijkstra 算法解决。这道题里面城市为结点,公路为边。一个复杂的问题是每一条边的权重,在这道题里有距离和收费两种权重,首先要找距离意义上最短路径,当最短路不止一条的时候,就需要找收费最短的路。
根据输入样例,有下面的图:
绿色表示权重距离,紫色表示权重收费。我们用基于 Dijkstra 算法的方法来解决,首先以距离为权重应用 Dijkstra 算法,我们知道到每收录一个结点的时候要判断其它结点有没有被影响,会不会得到一个更短的距离,如果更短的话我们要更新这个距离,如果是等长的话,在原本的 Dijkstra 算法中就什么都不做了,但在本题中,当距离相等的时候,我们还需要按照收费来做一个更新。
实现代码
#include<iostream>
using namespace std;
#define MaxNum 10000
typedef int ElemType;
int main()
{
int N,M;
ElemType S,D;
cin>>N>>M>>S>>D;
//用邻接矩阵存储图
int **len = new int*[N]; //储存公路长度
int **cost = new int*[N]; //储存费用
for(int i=0; i<N; i++)
{
len[i] = new int[N];
cost[i] = new int[N];
}
//初始化
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
len[i][j] = MaxNum;
cost[i][j] = MaxNum;
}
}
//构建邻接矩阵,处理输入数据
for(int i=0;i<M;i++)
{
ElemType c1,c2;
int l,c;
cin>>c1>>c2>>l>>c;
len[c1][c2] = l;
len[c2][c1] = l;
cost[c1][c2] = c;
cost[c2][c1] = c;
}
//Dijastra算法开始
int *dist = new int[N]; //记录当前路径长度
int *acost = new int[N]; //记录当前花费
//初始化
for(int i=0;i<N;i++)
{
dist[i] = MaxNum;
acost[i] = MaxNum;
}
dist[S] = 0;
acost[S] = 0;
//进行算法
for(int k=0;k<2;k++)
{
for(int v=0;v<N;v++)
{
for(int w=0;w<N;w++)
{
if(dist[v] != MaxNum)
{
if(dist[v]+len[v][w] < dist[w])
dist[w] = dist[v] + len[v][w];
else if(dist[v] + len[v][w] == dist[w] && acost[v] != MaxNum && acost[v]+cost[v][w] <acost[w])
acost[w] = acost[v] + cost[v][w];
}
}
}
}
cout<<dist[D] << " " <<acost[D] <<endl;
return 0;
}
提交结果
关于浙江大学MOOC数据结构课程的习题记录就到这里了,主要记录了线性表、树、图的必做编程题内容,附上课程大纲:
第一讲 基本概念(1:15:26)[陈越]1.1 什么是数据结构(4节共32:43)
1.2 什么是算法(3节共22:41)
1.3 应用实例:最大子列和问题(3节共20:02)
第二讲 线性结构(2:19:00)[何钦铭]
2.1 线性表及其实现(6小节共45:04)
2.2 堆栈(4小节共39:51)
2.3 队列(2小节共15:45)
2.4 应用实例:多项式加法运算(1小节10:37)
小白专场:多项式乘法与加法运算- C实现(3小节共27:43)
第三讲 树(上) (1:50:08)[何钦铭]
3.1 树与树的表示(5小节共38:54)
3.2 二叉树及存储结构(2小节共16:43)
3.3 二叉树的遍历(4小节共37:02)
小白专场:树的同构 - C语言实现(2小节共17:29)
第四讲 树(中)(1:06:31)[何钦铭]
4.1 二叉搜索树(3小节共20:57)
4.2 平衡二叉树(2小节共22:53)
小白专场:是否同一棵二叉搜索树- C实现(3小节共22:41)
线性结构之习题选讲[陈越]:Reversing Linked List(3小节共13:08)
第五讲 树(下)(1:53:28)[何钦铭]
5.1 堆(4小节共30:05)
5.2 哈夫曼树与哈夫曼编码(3小节共19:52)
5.3 集合及运算(2小节共12:57)
小白专场:堆中的路径 - C语言实现(1小节共7:51)
小白专场[陈越]:File Transfer - C语言实现(4小节共42:43)
第六讲 图(上)(1:29:32)[陈越]
6.1 什么是图(3小节共24:02)
6.2 图的遍历(4小节共22:22)
6.3 应用实例:拯救007(1小节共14:40)
6.4 应用实例:六度空间(1小节共8:06)
小白专场:如何建立图- C语言实现(6小节共20:22)
第七讲 图(中)(2:11:35)[陈越]
树之习题选讲-Tree Traversals Again(2小节共12:16)
树之习题选讲-Complete Binary Search Tree(3小节共25:47)
树之习题选讲- Huffman Codes(3小节共18:11)
7.1 最短路径问题(6小节共56:38)
小白专场:哈利•波特的考试- C语言实现(4小节共18:43)
第八讲 图(下)(57:02)[陈越]
8.1 最小生成树问题(2小节共20:16)
8.2 拓扑排序(2小节共27:57)
图之习题选讲-旅游规划(2小节共8:49)
第九讲 排序(上)(1:11:44)[陈越]
9.1 简单排序(冒泡、插入)(4小节共23:26)
9.2 希尔排序(1小节共9:29)
9.3 堆排序(2小节共10:27)
9.4 归并排序(3小节共28:22)
第十讲 排序(下)(54:20)[陈越]
10.1 快速排序(4小节共25:25)
10.2 表排序(2小节共12:41)
10.3 基数排序(3小节共12:13)
10.4 排序算法的比较(1小节共4:01)
第十一讲 散列查找(1:43:39)[何钦铭]
11.1 散列表(2小节共13:43)
11.2 散列函数的构造方法(2小节共13:05)
11.3 冲突处理方法(6小节共36:26)
11.4 散列表的性能分析(1小节10:26)
11.5 应用实例:词频统计(1小节6:01)
小白专场[陈越]:电话聊天狂人- C语言实现(4小节共23:58)
第十二讲 综合习题选讲(30:12) [陈越]
习题选讲-Insert or Merge(2小节共11:51)
习题选讲-Sort with Swap(0,*)(2小节共11:06)
习题选讲-Hashing - Hard Version(1小节共7:15)
最后给出一张数据结构和算法的思维导图:
剩下的内容将在之后的算法学习中进行。
参考链接:
06-图1 列出连通集 (25分)
07-图4 哈利·波特的考试(25 分)
旅游规划
$$$$
不足之处,欢迎指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。