算法课5-贪心算法(贪心在图中的应用)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/srping123/article/details/83538878

1. dijkstra算法
总体思路是使用一个距离数组来存储到源点的最小距离,每次找到距离数组中最小的那个点对应的距离和点,遍历这个点的邻接点,如果用这个点做跳板,距离更小的话,更新邻接点对应的距离数组。
在这里插入图片描述

int * dijkstra(int s, ALGraph & graph){
    for(int i=0;i<graph.vexNum;i++){
        visited[i]=-1;
    }
    int distance[graph.vexNum];
    fill(distance.begin(),distance.end(),INF);
    distance[s]=0;

    for(int i=0;i<graph.vexNum;i++){
        int u=-1;
        int min=INF;
        for(int j=0;j<graph.vexNum;j++){
            if(visited[j]==-1 && min>distance[j]){
                u=j;
                min=distance[j];
            }
        }
        if(u==-1){
            break;
        }
        visited[u]=1;
        ArcNode * firstarc=graph.adjList[u].firstarc;
        while(firstarc){
            int v =firstarc->adjvex;
            if(distance[v]>distance[u]+firstarc->weight){
                distance[v]=distance[u]+firstarc->weight;
            }
            firstarc=firstarc->next;
        }
    }
    return distance;
}

使用stl中的priority_queue可以加快速度,参考代码
https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-using-priority_queue-stl/

注意decrease-key的优先队列实现,以及pair的使用


// Program to find Dijkstra's shortest path using 
// priority_queue in STL 
#include<bits/stdc++.h> 
using namespace std; 
# define INF 0x3f3f3f3f 
  
// iPair ==>  Integer Pair 
typedef pair<int, int> iPair; 
  
// This class represents a directed graph using 
// adjacency list representation 
class Graph 
{ 
    int V;    // No. of vertices 
  
    // In a weighted graph, we need to store vertex 
    // and weight pair for every edge 
    list< pair<int, int> > *adj; 
  
public: 
    Graph(int V);  // Constructor 
  
    // function to add an edge to graph 
    void addEdge(int u, int v, int w); 
  
    // prints shortest path from s 
    void shortestPath(int s); 
}; 
  
// Allocates memory for adjacency list 
Graph::Graph(int V) 
{ 
    this->V = V; 
    adj = new list<iPair> [V]; 
} 
  
void Graph::addEdge(int u, int v, int w) 
{ 
    adj[u].push_back(make_pair(v, w)); 
    adj[v].push_back(make_pair(u, w)); 
} 
  
// Prints shortest paths from src to all other vertices 
void Graph::shortestPath(int src) 
{ 
    // Create a priority queue to store vertices that 
    // are being preprocessed. This is weird syntax in C++. 
    // Refer below link for details of this syntax 
    // https://www.geeksforgeeks.org/implement-min-heap-using-stl/ 
    priority_queue< iPair, vector <iPair> , greater<iPair> > pq; 
  
    // Create a vector for distances and initialize all 
    // distances as infinite (INF) 
    vector<int> dist(V, INF); 
  
    // Insert source itself in priority queue and initialize 
    // its distance as 0. 
    pq.push(make_pair(0, src)); 
    dist[src] = 0; 
  
    /* Looping till priority queue becomes empty (or all 
      distances are not finalized) */
    while (!pq.empty()) 
    { 
        // The first vertex in pair is the minimum distance 
        // vertex, extract it from priority queue. 
        // vertex label is stored in second of pair (it 
        // has to be done this way to keep the vertices 
        // sorted distance (distance must be first item 
        // in pair) 
        int u = pq.top().second; 
        pq.pop(); 
  
        // 'i' is used to get all adjacent vertices of a vertex 
        list< pair<int, int> >::iterator i; 
        for (i = adj[u].begin(); i != adj[u].end(); ++i) 
        { 
            // Get vertex label and weight of current adjacent 
            // of u. 
            int v = (*i).first; 
            int weight = (*i).second; 
  
            //  If there is shorted path to v through u. 
            if (dist[v] > dist[u] + weight) 
            { 
                // Updating distance of v 
                dist[v] = dist[u] + weight; 
                pq.push(make_pair(dist[v], v)); 
            } 
        } 
    } 
  
    // Print shortest distances stored in dist[] 
    printf("Vertex   Distance from Source\n"); 
    for (int i = 0; i < V; ++i) 
        printf("%d \t\t %d\n", i, dist[i]); 
} 

2. Prim算法
在这里插入图片描述
Prim和dijstra的不同之处,只有if判断时不同
思路是找最小的边,不断更新,blue rule的应用
维护一个cost数组和一个存最小生成树的邻接数组

void prim(int start,ALGraph & graph)
{
    int sumweight=0;
    int i,j,k=0;
    
    int lowcost[graph.vexNum];
    int adjecent[graph.vexNum];


    for(i=0;i<graph.vexNum;i++)                                     
    {
        lowcost[i]=graph.adjList[i].firstarc->weight;
        visited[i]=-1;                                         //将所有点至于Vnew之外,V之内,这里只要对应的为-1,就表示在Vnew之外
    }

    visited[start]=0;                                        //将起始点start加入Vnew
    adjecent[start]=start;

    for(i=0;i<graph.vexNum-1;i++)
    {
        int min=INF;
        int v=-1;
        for(j=0;j<graph.vexNum;j++)
        {
            if(visited[j]!=-1&&lowcost[j]<min)                 //在Vnew之外寻找最短路径
            {
                min=lowcost[j];
                v=j;
            }
        }
        if(v!=-1)
        {
            printf("%d %d %d\n",adjecent[v],v,lowcost[v]);
            visited[v]=1;                                      //将v加Vnew中

            sumweight+=lowcost[v];                             //计算路径长度之和

            ArcNode * firstarc=graph.adjList[v].firstarc;
            while(firstarc){
                int v =firstarc->adjvex;
                if(visited[j]==-1&&firstarc->weight<lowcost[j]){
                    lowcost[j]=firstarc->weight;                     //此时v点加入Vnew 需要更新lowcost
                    adjecent[j]=v;
                }
                firstarc=firstarc->next;
            }
         
        }
    }
    printf("the minmum weight is %d",sumweight);
}

3. Kruskal算法
在这里插入图片描述
kruskal算法主要依靠并查集实现,下次课将涉及并查集相关知识
主要思想是把所有边进行排序,每次找最小的边,检查当前的边的两个端点是否在同一个连通分量中,如果不是,则将这个边加入MST中。
以下代码参考https://blog.csdn.net/luomingjun12315/article/details/47700237

//n为边的数量,m为村庄的数量
int Kruskal(int n, int m){
    int nEdge = 0, res = 0;
    //将边按照权值从小到大排序
    qsort(a, n, sizeof(a[0]), cmp);
    for(int i = 0; i < n && nEdge != m - 1; i++){
        //判断当前这条边的两个端点是否属于同一棵树
        if(find(a[i].a) != find(a[i].b)){
            unite(a[i].a, a[i].b);
            res += a[i].price;
            nEdge++;
        }
    }
    //如果加入边的数量小于m - 1,则表明该无向图不连通,等价于不存在最小生成树
    if(nEdge < m-1) res = -1;
    return res;
}

4. Reverse-delete算法
真正的red rule按照red rule去实现,但因为复杂度过高,没有什么应用。

猜你喜欢

转载自blog.csdn.net/srping123/article/details/83538878
今日推荐