6.图 Dijsktra, Prim,Kruskal,包括堆优化

特殊矩阵的压缩存储

对称矩阵的压缩存储

只存储主对角线+上\下半角

按照行优先或者列优先存储

三角矩阵的压缩存储

跟对称矩阵相同的思想

稀疏矩阵的压缩存储

  • 三元组方式存储
  • 十字链表法

图的基本概念

图G比顶点集边集日且成,记为G=(V,E),其中v(G)表示图G中顶点的有限非空集;E(G)表示图G中顶点之间的关系(边)集合。若V={v, vs… , vn,},则用V]表示图G中顶点的个数,也称图G的阶,E= {(u, v) | ueV,vev},用|E|表示图G中边的条数。

最小生成树

Prim算法

从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。

Kruskal算法

每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选)直到所有结点都连通

最短路径

BFS(无权图) 单源最短路径

Dijkstra(带权图, 无权图) 单源最短路径 不适合带负权的图

Floyd(带权图,无权图) 各顶点间的最短路径 不能解决带负权回路的图

拓扑排序

AOV网(Activity on vertex Network,用顶点表示活动的网)
用DAG图〈有向无环图)表示一个工程。顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行

拓扑排序︰在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:
1每个顶点出现且只出现一次。2若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。 或定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。

逆拓扑排序:先删除入度为0的点

在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销〈如完成活动所需的时间),称之为用边表示活动的网络,简称AOE网(Activity On Edge NetWork)

关键路径

AOE网具有以下两个性质︰
①只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始; ②只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。另外,有些活动是可以并行进行的

在AOE网中仅有一个入度为0的顶点,称为开始顶点(源点),它表示整个工程的开始;
也仅有一个出度为0的顶点,称为结束顶点(汇点),它表示整个工程的结束。

从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动

Graph.h

#ifndef _GRAPH_H_
#define _GRAPH_H_

#include <iostream>
#include <vector>

//无向图,邻接矩阵
class UMGraph
{
public:
    UMGraph(const int v, const int e) : __INF(99999999)
    {
        this->vertex = v; 
        this->edge = e;
        for(int i = 0; i <= vertex; ++ i)
            visited.push_back(false);
        for(int i = 0; i <= vertex; ++ i)
            graph.push_back(std::vector<int>(vertex+1, __INF));
        // for(int i = 1; i <= vertex; ++ i)
        //     graph[i][i] = 0;
    }

public:
    int getV(){ return vertex; }
    int getE(){ return edge; }
    void getGraph();

public:
    void Insert();
    bool Delete();
    void DFSTravel(std::vector<int> &);
    void BFSTravel(std::vector<int> &);
    void Dijkstra(std::vector<int> &, std::vector<int> &);
    void Dijkstraheap(std::vector<int> &, std::vector<int> &);
    void Prim(int &cost, bool flag = 1);
    void Primheap(int &cost, bool flag = 1);
    void Kruskal(int &cost);

private:
    void __Insert(const int u, const int v, const int weight);
    bool __Delete(const int u, const int v);
    void __DFSTravel(const int u, std::vector<int> &);
    void __BFSTravel(const int u, std::vector<int> &);
    void __Dijkstra(const int u, std::vector<int> &, std::vector<int> &);
    void __Dijkstraheap(const int u, std::vector<int> &, std::vector<int> &);
    void __Prim(int &cost, bool flag);
    void __Primheap(int &cost, bool flag);
    int find_father(int x, std::vector<int> &fat);
    void __Kruskal(int &cost);

public:
    int vertex, edge;
    const long long __INF;
    std::vector<bool> visited;
    std::vector<std::vector<int> > graph;
};


//无向图,邻接表



//有向图,邻接矩阵



//有向图,邻接表


#endif //_GRAPH_H_

Graph.cpp

#include "Graph.h"
#include <iostream>
#include <queue>
#include <algorithm>

void UMGraph::getGraph()
{   
    for(int i = 1; i <= vertex; ++ i)
    {
        for(int j = 1; j <= vertex; ++ j)
            std::cout << graph[i][j] << " ";
        std::cout << std::endl;
    }
}

void UMGraph::Insert()
{
    std::cout << "Input your node v form u and weight: ";
    int un, vn, w;
    std::cin >> un >> vn >> w;
    __Insert(un, vn, w);
}

void UMGraph::__Insert(const int u, const int v, const int weight)
{
    //int tmp = std::min(weight, graph[u][v]);
    graph[u][v] = graph[v][u] = std::min(weight, graph[u][v]);
}

bool UMGraph::Delete()
{
    std::cout << "Input you'll delete two nodes: ";
    int un, vn;
    std::cin >> un, vn;
    return __Delete(un, vn);
}

bool UMGraph::__Delete(const int u, const int v)
{
    if(graph[u][v] != __INF && graph[v][u] != __INF)
    {
        return false;
    }
    graph[u][v] = graph[v][u] = __INF;
    return false;
}

void UMGraph::DFSTravel(std::vector<int> &p)
{
    std::cout << "Input you'll DFSTravel first node: ";
    int un;
    std::cin >> un;
    for(auto x : visited)
        x = false;
    //std::cout << "The DFS sequence is: \n";
    __DFSTravel(un, p);
    //std::cout << "\n";
}

void UMGraph::__DFSTravel(const int u, std::vector<int> &p)
{
    visited[u] = true;
    //std::cout << u << " ";
    p.push_back(u);
    for(int i = 1; i <= vertex; ++ i)
    {
        if(!visited[i] && graph[u][i] != __INF && graph[i][u] != __INF)
        {
            visited[i] = true;
            __DFSTravel(i, p);
        }
    }
}

void UMGraph::BFSTravel(std::vector<int> &p)
{
    std::cout << "Input you'll BFSTravel first node: ";
    int un;
    std::cin >> un;
    for(auto x : visited)
        x = false;
    //std::cout << "The BFS sequence is: \n";
    __BFSTravel(un, p);
    //std::cout << "\n";
}

void UMGraph::__BFSTravel(const int u, std::vector<int> &p)
{
    //std::cout << u << " ";
    p.push_back(u);
    std::queue<int> q;
    q.push(u);
    visited[u] = 1;
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        for(int i = 1; i <= vertex; ++ i)
        {
            if(!visited[i] && graph[t][i] != __INF && graph[i][t] != __INF)
            {
                visited[i] = true;
                q.push(i);
                //std::cout << i << " ";
                p.push_back(i);
            }
        }
    }
}

void UMGraph::Dijkstra(std::vector<int> &dis, std::vector<int> &path)
{
    std::cout << "Input you'll begin from: ";
    int un;
    std:: cin >> un;
    dis.push_back(0);
    path.push_back(0);
    for(int i = 1; i <= vertex; ++ i)
    {
        dis.push_back(graph[un][i]);
        visited[i] = false;
        if(dis[i] == __INF)
            path.push_back(-1);
        else 
            path.push_back(un);
    }
    dis[un] = 0;
    visited[un] = true;
    __Dijkstra(un, dis, path);
    //std::cout << "The shortest dis from u to other is: \n";
    // for(auto x : dis)
    //     std::cout << x << " ";
    // std::cout << "\n";
    // for(auto x : path)
    //     std::cout << x << " ";
    // std::cout << "\n";
    // for(int i = 1; i <= vertex; ++ i)
    //     std::cout << dis[i] << " ";
    // std::cout << "\n";
    // for(int i = 1; i <= vertex; ++ i)
    //     std::cout << path[i] << " ";
    // std::cout << "\n";
}

void UMGraph::__Dijkstra(const int u, std::vector<int> &dis, std::vector<int> &path)
{
    for(int i = 1; i <= vertex; ++ i)
    {
        int t = u, tmp = __INF;
        for(int j = 1; j <= vertex; ++ j)
            if(!visited[j] && tmp > dis[j])
            {
                tmp = dis[j];
                t = j;
            }
        
        if(t == vertex) break;
        visited[t] = true;

        for(int j = 1; j <= vertex; ++ j)
        {
            if(!visited[j] && graph[t][j] < __INF)
            {
                if(dis[j] > dis[t]+graph[t][j])
                {
                    dis[j] = dis[t]+graph[t][j];
                    path[j] = t;
                }
            }
        }
    }
}

void UMGraph::Dijkstraheap(std::vector<int> &dis, std::vector<int> &path)
{
    std::cout << "Input you'll begin from: ";
    int un;
    std:: cin >> un;
    //占位
    dis.push_back(0);
    path.push_back(0);
    //初始化
    for(int i = 1; i <= vertex; ++ i)
    {
        dis.push_back(__INF);
        visited[i] = false;
        if(dis[i] == __INF)
            path.push_back(-1);
        else 
            path.push_back(un);
    }
    dis[un] = 0;
    __Dijkstraheap(un, dis, path);

    //std::cout << "The shortest dis from u to other is: \n";
    // for(auto x : dis)
    //     std::cout << x << " ";
    // std::cout << "\n";
    // for(auto x : path)
    //     std::cout << x << " ";
    // std::cout << "\n";
    // for(int i = 1; i <= vertex; ++ i)
    //     std::cout << dis[i] << " ";
    // std::cout << "\n";
    // for(int i = 1; i <= vertex; ++ i)
    //     std::cout << path[i] << " ";
    // std::cout << "\n";
}

void UMGraph::__Dijkstraheap(const int u, std::vector<int> &dis, std::vector<int> &path)
{
    typedef struct Node
    {
        int u, step;
        Node() {};
        Node(int a, int b) : u(a), step(b) {};
        bool operator<(const Node &t) const
        {
            return step > t.step;
        }
    }Node;

    std::priority_queue<Node> pq;
    pq.push(Node(u, 0));

    while(!pq.empty())
    {
        Node it = pq.top();
        pq.pop();
        int t = it.u;
        if(visited[t])  continue;  //找到了
        visited[t] = 1;
        for(int i = 1; i <= vertex; ++ i)
        {
            if(!visited[i] && graph[t][i] < __INF)
            {
                if(dis[i] > dis[t]+graph[t][i])
                {
                    dis[i] = dis[t]+graph[t][i];
                    path[i] = t;
                    pq.push(Node(i, dis[i]));
                }
            }
        }
    }
}

void UMGraph::Prim(int &cost, bool flag)
{
    __Prim(cost, flag);
}

void UMGraph::__Prim(int &cost, bool flag)
{
    std::vector<int> lowcost(vertex+1, 0), mit(vertex+1, 1);

    for(int i = 1; i <= vertex; ++ i)
    {
        lowcost[i] = graph[1][i];
        mit[i] = 1;
    } 
    mit[1] = 0;

    int idx = 1;

    cost = 0;

    for(int i = 2; i <= vertex; ++ i)
    {
        int minn = __INF, t = 0;
        for(int j = 2; j <= vertex; ++ j)
        {
            if(lowcost[j] < minn && lowcost[j] != 0)
            {
                minn = lowcost[j];
                t = j;
            }
        }

        if(flag == 1)
        {
            printf("%d --> %d  w: %d\n", mit[t], t, minn);
        }
        cost += minn;
        lowcost[t] = 0;

        for(int j = 2; j <= vertex; ++ j)
        {
            if(graph[t][j] < lowcost[j])
            {
                lowcost[j] = graph[t][j];
                mit[j] = t; //更新前驱
            }
        }
    }
}

void UMGraph::Primheap(int &cost, bool flag)
{
    __Primheap(cost, flag);
}


void UMGraph::__Primheap(int &cost, bool flag)
{

    typedef struct node
    {
        int weight, u;
        node(int w, int u1) : weight(w), u(u1) {};
        bool operator<(const node &a) const
        {
            return weight > a.weight;
        }
    }node;
    std::vector<int> path(vertex+1, -1);
    path[1] = 1;
    std::vector<int> lowcost(vertex+1, __INF);
    for(int i = 0; i <= vertex; ++ i)
    {
        visited[i] = 0;
        lowcost[i] = __INF;
    }
    cost = 0;

    std::priority_queue<node> pq;

    pq.push(node(0, 1));

    while(!pq.empty())
    {
        node t = pq.top();
        pq.pop();
        int d = t.weight, v = t.u;

        if(visited[v]) continue;
        visited[v] = true;
        cost += d;
        for(int i = 1; i <= vertex; ++ i)
        {
            if(!visited[i] && lowcost[i] > graph[v][i])
            {
                lowcost[i] = graph[v][i];
                pq.push(node(lowcost[i], i));
                path[i] = v;
            }
        }
    }
    if(flag == 1)
    {
        for(int i = 1; i <= vertex; ++ i)
            std::cout << path[i] << " ";
        std::cout << "\n";
    }
}

int UMGraph::find_father(int x, std::vector<int> &fat)
{
    if(fat[x] != x)
        return find_father(fat[x], fat);
    return x;
}

void UMGraph::Kruskal(int &cost)
{
    __Kruskal(cost);
}

void UMGraph::__Kruskal(int &cost)
{
    std::vector<int> fat(vertex+1, 0);
    for(int i = 1; i <= vertex; ++ i)
        fat[i] = i;
    typedef struct Edge
    {
        int u, v, w;
        bool operator<(const Edge &a) const
        {
            return w < a.w;
        }
    }Edge;

    Edge arr[edge+1];
    int idx = 1;
    for(int i = 1; i <= vertex;  ++ i)
    {
        for(int j = i; j <= vertex; ++ j)
        {
            if(graph[i][j] != __INF)
            {
                arr[idx].u = i; arr[idx].v = j; arr[idx].w = graph[i][j];
                idx ++;
            }
        }
    }
    // for(int i = 1; i <= edge; ++ i)
    //     std::cout << arr[i].u << " " << arr[i].v << " " << arr[i].w << "\n";
    std::sort(arr+1, arr+1+edge);
    // std::cout << "\n";
    // for(int i = 1; i <= edge; ++ i)
    //     std::cout << arr[i].u << " " << arr[i].v << " " << arr[i].w << "\n";
    // std::cout << "\n";    
    int num = 0;
    for(int i = 1; i <= edge; ++ i)
    {
        if(num == vertex-1) break;
        int u, v, w;
        u = arr[i].u; v = arr[i].v; w = arr[i].w;
        if(find_father(u, fat) != find_father(v, fat))
        {
            fat[find_father(u, fat)] = find_father(v, fat);
            cost += w;
            num ++;
        }
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值