图之拯救007
这一章学习了图。
一、图的基本概念与原理
-
有向图与无向图;
顶点
弧:弧尾和弧头
度:出度和入度
顶点
边
邻接点
连通图
完全图:边数=n(n-1)/2
生成树:边数=n-1
-
图的表示法
-
图的遍历
-
最小生成树:注意最小生成树的应用
二、图的存储方式
对于无向图:存储顶点及边
对于有向图:存储顶点及弧
弧尾———-权值———弧尾
邻接矩阵
顶点的表示方法:
顶点索引 顶点数据
弧的表示方法:
邻接矩阵
顶点的表示方法:
顶点索引 出弧链表头指针 顶点数据
弧的表示方法:
弧头顶点索引 下一条弧指针 弧数据
最难理解的是出弧链表头指针及下一条弧指针
一个顶点发出多条弧时,第一条弧里带有下一条弧的指针;
弧数据相当于权重
十字链表
也用于存储有向图;
顶点的表示方法
顶点索引 顶点数据 以该顶点为弧尾的弧节点指针 以该顶点为弧头的弧节点指针
弧的表示方法
弧尾顶点索引 弧头顶点索引 弧尾相同的下一条弧的指针 弧头相同的下一条弧的指针 弧的数据
邻接多重表
用于存储无向图;
顶点的表示方法
顶点索引 连接该顶点的边 顶点数据
边的表示方法
三、图的遍历
图的搜索按搜索方向分为:深度优先搜索和广度优先搜索;
深度优先搜索遵循二叉树搜索的“根左右”的原则,广度优先搜索是一层一层的节点进行搜索;
1、最小生成树
有普利姆算法,克鲁斯卡尔算法两种算法;普里姆是归并点;而克鲁斯卡尔是归并边;
普利姆(prim)算法
算法思想:
[ ] 任意选择一个顶点,将其放入点集合中;下图选的顶点为A;
[ ] 将与A顶点相连的边放入待选边集合中,如下图的A-B(6) A-F(1) A-E(5)所示;
[ ] 选择一个权值最小的边放入边集合中,下图中是A-F(1);将该边所连的顶点F放入点集合中;
[ ] 将与F点相连的边放入待选边集合中,如F-B(2) F-E(9) F-C(8) F-D(4),重复上面2~3步的过程,直到所有的点都被包含在点集合中(图中的点集合少写了个E)
[ ] 普利姆算法适用于稠密的图,即边数较多的图,时间复杂度o(n^2);
克鲁斯卡尔(Kruskal)算法
算法思想:
[ ] 将所有边放入待选边集合中;
[ ] 取出当前待选边集合中权值最小的边放入已选边集合中,将边所连接的两个顶点放入已涉及点集合中
[ ] 重复步骤2,如果已涉及的点的集合中的点不处于同一棵树中,则继续重复步骤2,直到已涉及的点的集合包含所有的点且所有点都在同一棵树中,最小生成树也就随之产生了;
[ ] 克鲁斯卡尔算法适用于边数较少的稀疏图,算法复杂度为o(n^2);
拯救007
#include <iostream> #include <algorithm> #include <vector> #include <set> #include <cstdio> #include <cstdlib> #include <vector> #include <string> #include <cstring> #include <cmath> using namespace std; const int maxn=150; struct Node { double x,y; } node[maxn]; double d_len(int x,int y) { double xx=node[x].x-node[y].x;//两点之间x坐标间距离 double yy=node[x].y-node[y].y;//两点之间y坐标间距离 return sqrt(xx*xx+yy*yy);//对距离求平方,比较平方可减少不必要麻烦 } int n; double d; double G[maxn][maxn]; int f; int vis[maxn]; void dfs(int x) { if(vis[x]) return ; vis[x]=1; double xx=fabs(node[x].x-50); double yy=fabs(node[x].y-50); if(xx<=d||yy<=d)//判断007是否可以直接跳到对岸 { f=1; return ; } for(int i=0; i<n; i++)//确定007逃生路径 { if(vis[i]) continue; if(G[x][i]<=d) { dfs(i); } } } int main() { cin>>n>>d; f=0; for(int i=0; i<n; i++) { cin>>node[i].x>>node[i].y;//输入鳄鱼的坐标 } for(int i=0; i<n; i++) { for(int j=i; j<n; j++) { G[i][j]=G[j][i]=d_len(i,j); } } if(d>=(50-15))//直接跳过去对岸 { cout<<"Yes"<<endl; return 0; } for(int i=0; i<n; i++) { double x=fabs(node[i].x-15);//返回绝对值 double y=fabs(node[i].y-15);//返回绝对值 if(x<=d||y<=d)//满足条件,进行下一步跳跃 { memset(vis,0,sizeof(vis));//memset函数,将vis中的内容用0替换并返回 dfs(i); } } if(f) cout<<"Yes"<<endl; else cout<<"No"<<endl; return 0; }
思路:直接暴力就行,最多只有一百个鱼,一开始没有思路,后来想想用一个简单的dfs即可。
上次目标是复习第四章第五章,有进行复习,但还要继续,这次目标就定为多打打树和图的代码,熟悉两者的运用。加油!