①图的遍历
图的遍历一般分为深度遍历和广度遍历,具体适用范围根据题意来定。
1.DFS(深度遍历)
深度遍历的实现就是通过递归完成,
模板如下:
void dfs(int x){
if(check()){
/****/; //遍历的过程中,某节点满足条件则直接操作
return;
}
for (int i = 1; i<=n; i++){
if(!vis(i) && judge(i)){ //如果某节点符合继续往下遍历的条件,则进入下一层dfs
dfs(i);
}
}
}
//条件可以分为:比如在迷宫中,则judge可以为判断上下左右四个方向是否可行等等
2.BFS(广度遍历)
广度遍历,一般用于需要记录走几步,最小跳次数之类的。
模板如下:
void bfs(int x){//x为起点
vis[x]= 1;
queue<int> q;
q.push(x);
int tmp, level = 1,start = x,tail;
while(!q.empty()){
tmp = q.front();
q.pop();
if(条件满足) 输出;
for (int i = 1; i <=n; i++){
if(!vis[i] && judge(i)){
q.push(i);
vis[i] = 1;
tail = i;
}
}
if(start == tmp){
start = tail;
level++;
}
}
}
②Dijkstra单源最短路径
第一种,采用邻接矩阵的方式存储整个图,所以对点的个数要求比较苛刻,容易MLE,爆内存
const int INF = 1000000;
int Map[maxn][maxn]; //地图,节点值为两点之间距离,赋值前为INF
int vis[maxn];//记录节点是否被访问
int dis[maxn];//记录源点到其余所有点的最近距离
int Prev[maxn];//记录每个点前一个连接节点,用于返回路径
void dijkstra(int x){
for (int i = 1; i<=n; i++){
dis[i] = Map[x][i];
}
dis[x] = 0;
vis[x] = 1;
int tmp, k;
for (int i = 1; i <= n; i++){
tmp = INF;
k = -1;
for (int j = 1; j <= n; j++){
if(!vis[j] && dis[j] < tmp){//找出未访问的节点中距离源点最近的
tmp = dis[j];
k = j;
}
}
if(j == - 1)return;//如果全部都访问过,直接返回
vis[k]= 1;//由反证法可证明,每次找到的最小的dis就是该点距离源点最小的距离
for (int j = 1; j <= n; j++){//来更新未被访问的节点的dis
if(!vis[j] && dis[k] + Map[k][j] < dis[j]){
dis[j] = dis[k] + Map[k][j];
Prev[j] = k;
}
}
}
}
第二种,采用邻接矩阵的方式存储边,直接上代码,如果看完代码还不知道结构体是如何定义的,请手动模拟试一下每个数组的意义,最多三个点,你会清晰的了解到(QAQ,因为我也是这样过来的,太笨了TvT~~~);;代码如下:
边的结构体如下:
struct Node{
int to;
int val;
int next;
}edge[500005];
#include<bits/stdc++.h>
using namespace std;
const int INF = 2147483647;
const int maxn = 10010;
struct Node{
int to;
int val;
int next;
}edge[500005];
int head[maxn];
int vis[maxn];
int dis[maxn];
int n,m,s,cnt = 0;
void add(int x,int y,int val){
cnt++;
edge[cnt].to = y; //节点x所指向的节点y
edge[cnt].val = val; //val就是边权
edge[cnt].next = head[x]; // 该节点的next 是指向下一个边的头结点
head[x] = cnt; //更新头结点,这个插入方式是前插,,手动模拟一下,就很容易明白
}
int main(){
cin>>n>>m>>s;
int x, y, val;
for (int i = 1; i<=m; i++){
scanf("%d %d %d",&x,&y,&val);
add(x, y, val);
}
for (int i = 1; i<=n;i++)
dis[i] = INF;
memset(vis,0,sizeof(vis));
dis[s] = 0;
int tmp;
while(!vis[s]){
vis[s] = 1;
for (int i = head[s]; i!=0; i = edge[i].next){
//注意if判断,,由于是从一个固定头结点s,向s指向的节点逐个判断,所以距离是dis[s] + edge[i].val
if(!vis[edge[i].to] && dis[edge[i].to] > dis[s] + edge[i].val){
dis[edge[i].to] = dis[s] + edge[i].val;
}
}
tmp = INF;
for (int i = 1; i<=n; i++){//找到最小的dis,进行继续遍历,与邻接矩阵的一样
if(!vis[i] && dis[i]<tmp){
tmp = dis[i];
s = i;
}
}
}
for (int i = 1; i <= n; i++){
cout << dis[i] << " ";
}
return 0;
}