图论-Dijkstra单源最短路径,bfs以及dfs

①图的遍历
图的遍历一般分为深度遍历和广度遍历,具体适用范围根据题意来定。
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
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;
}

你可能感兴趣的:(图论-Dijkstra单源最短路径,bfs以及dfs)