稠密图(邻接矩阵),并查集,最短路径(Dijkstra,spfa),最小生成树(kruskal,prim)

全部函数通过杭电 1142,1162,1198,1213等题目测试。

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
using namespace std;

/*
//函数集合声明下,方便查看
void Dijkstra(const denseGraph& dg, int s);
void spfa(const denseGraph& dg, int s);
weightType prim(const denseGraph& dg, int s);
void makeSet(int x);
int findSet(int x);
void unionSet(int x, int y);
weightType kruskal(const denseGraph& dg);
*/

//稠密图,邻接矩阵表示
#define N 1000            //表示顶点数最大值
#define NOEDGE 1000000    //表示无边,用于距离类求解中
typedef double weightType;    //表示带边权的类型
//定义带权边类
struct edge{
    int v, w;
    weightType val;
    edge(int v = -1, int w = -1, weightType val = NOEDGE) :v(v), w(w), val(val){}
};
//定义稠密图类
struct denseGraph{
    int Vcnt, Ecnt;    //顶点数,边数
    bool dg;    //有向图 ? 
    vector< vector<weightType> > adj;    //邻接矩阵
    denseGraph(int v, bool dg = false) :adj(v), Vcnt(v), Ecnt(0), dg(dg){
        for (int i = 0; i < v; ++i)
            adj[i].assign(v, NOEDGE);
    }
    void insert(edge e){
        int v = e.v, w = e.w;
        weightType val = e.val;
        if (adj[v][w] == NOEDGE) ++Ecnt;
        adj[v][w] = val;
        if (!dg) adj[w][v] = val;
    }
    void show(){
        printf("Vcnt = %d, Ecnt = %d, Directed : %d\n", Vcnt, Ecnt, dg);
        for (int i = 0; i < Vcnt; ++i){
            for (int j = 0; j < Vcnt-1; ++j)
                cout << adj[i][j] << ' ';
            cout << adj[i][Vcnt - 1] << endl;
        }
    }
};

//Dijkstra算法
weightType dDijkstra[N];    //存放所有顶点到 s 的最短路径距离
int pDijkstra[N];        //pDijkstra[i],路径存在时,存放节点 i 的前驱,不存在时,-1
void Dijkstra(const denseGraph &dg, int s)
{
    bool visit[N];    //集合 S ,visit[i]=true, i 属于集合 S 
    for (int i = 0; i < dg.Vcnt; ++i){    //初始化
        visit[i] = false;
        dDijkstra[i] = dg.adj[s][i];
        pDijkstra[i] = dDijkstra[i] == NOEDGE ? -1 : s;
    }
    visit[s] = true; dDijkstra[s] = 0;
    for (int i = 0; i < dg.Vcnt - 1; ++i){    //dg.Vcnt-1次选点
        int min = NOEDGE;
        int v = 0;
        for (int j = 0; j < dg.Vcnt; ++j){    //选距离最近点
            if (!visit[j] && dDijkstra[j] < min){
                v = j; min = dDijkstra[j];
            }
        }
        visit[v] = true;
        for (int j = 0; j < dg.Vcnt; ++j){        //更新与 v 直接相连的顶点
            if (!visit[j] && min + dg.adj[v][j] < dDijkstra[j]){
                dDijkstra[j] = min + dg.adj[v][j];
                pDijkstra[j] = v;
            }
        }

    }
}

//最短路径 SPFA算法
weightType dSpfa[N];
int pSpfa[N];
void spfa(const denseGraph& dg, int s)
{
    bool visit[N];
    for (int i = 0; i < dg.Vcnt; ++i){
        visit[i] = false;
        dSpfa[i] = NOEDGE;
        pSpfa[i] = -1;
    }
    dSpfa[s] = 0;
    int u;
    queue<int> q;
    q.push(s);
    while (!q.empty()){
        u = q.front(); q.pop();
        for (int i = 0; i < dg.Vcnt; ++i){
            if (dSpfa[u] + dg.adj[u][i] < dSpfa[i]){
                dSpfa[i] = dSpfa[u] + dg.adj[u][i];
                pSpfa[i] = u;
                if (!visit[i])
                    q.push(i);
            }
        }
    }
}

//最小生成树 prim
weightType dPrim[N];    //存放所有顶点到 s 的最短路径距离
weightType prim(const denseGraph& dg, int s)
{
    weightType sum = 0;
    bool visit[N];
    for (int i = 0; i < dg.Vcnt; ++i){    //初始化
        visit[i] = false;
        dPrim[i] = dg.adj[s][i];
    }
    visit[s] = true; dPrim[s] = 0;
    for (int i = 0; i < dg.Vcnt - 1; ++i){
        weightType min = NOEDGE;
        int v = 0;
        for (int j = 0; j < dg.Vcnt; ++j){    //选点
            if (!visit[j] && dPrim[j] < min){
                v = j; min = dPrim[j];
            }
        }
        sum += min;
        visit[v] = true;
        for (int j = 0; j < dg.Vcnt; ++j){
            if (!visit[j] && dg.adj[v][j] < dPrim[j]){
                dPrim[j] = dg.adj[v][j];
            }
        }
    }
    return sum;
}


//并查集实现,点集[0,1,2,3,4,...,n-1]
int parentSet[N];
int rankSet[N];
void makeSet(int x)
{
    parentSet[x] = x;
    rankSet[x] = 0;
}
void linkSet(int x, int y)
{
    if (rankSet[x] > rankSet[y])
        parentSet[y] = x;
    else {
        parentSet[x] = y;
        if (rankSet[x] == rankSet[y])
            ++rankSet[y];
    }
}
int findSet(int x)
{
    vector<int> v;
    while (parentSet[x] != x){
        v.push_back(x);
        x = parentSet[x];
    }
    for (int i = 0; i < v.size(); ++i)
        parentSet[v[i]] = x;
    return x;
}
void unionSet(int x, int y)
{
    linkSet(findSet(x), findSet(y));
}

//最小生成树 kruskal
bool kruskalComp(const edge& a, const edge& b)
{
    return a.val < b.val;
}
weightType kruskal(const denseGraph& dg)
{
    weightType sum = 0;
    edge e;
    vector<edge> ve;
    for (int i = 0; i < dg.Vcnt; ++i)
        for (int j = 0; j <= i; ++j)
            if (dg.adj[i][j]!=NOEDGE)
                ve.push_back(edge(i, j, dg.adj[i][j]));
    if (dg.dg){
        for (int i = 0; i < dg.Vcnt; ++i)
            for (int j = i + 1; j < dg.Vcnt; ++j)
                if(dg.adj[i][j]!=NOEDGE)
                    ve.push_back(edge(i, j, dg.adj[i][j]));
    }
    sort(ve.begin(), ve.end(), kruskalComp);

    for (int i = 0; i < dg.Vcnt; ++i)
        makeSet(i);

    for (int i = 0; i < ve.size(); ++i){
        e = ve[i];
        int x = findSet(e.v);
        int y = findSet(e.w);
        if (x != y){
            unionSet(x, y);
            sum += e.val;
        }
    }
    return sum;
}



/*测试数据
5 6
1 3 2
1 4 2
3 4 3
1 5 12
4 2 34
5 2 24

7 8
1 3 1
1 4 1
3 7 1
7 4 1
7 5 1
6 7 1
5 2 1
6 2 1
*/
int main()
{
    int v, w, val, n, m;
    cin >> n >> m;
    denseGraph dg(n,true);
    while (m--){
        cin >> v >> w >> val;
        dg.insert(edge(v - 1, w - 1, val));
    }
    dg.show();
    cout << endl;
    for (int i = 0; i < dg.Vcnt; ++i){
        spfa(dg, i);
        Dijkstra(dg, i);
        for (int i = 0; i < dg.Vcnt; ++i)
            cout << dSpfa[i] << ' ';
        cout << endl;
        for (int i = 0; i < dg.Vcnt; ++i)
            cout << dDijkstra[i] << ' ';
        cout << endl;

        for (int i = 0; i < dg.Vcnt; ++i)
            cout << pSpfa[i] << ' ';
        cout << endl;
        for (int i = 0; i < dg.Vcnt; ++i)
            cout << pDijkstra[i] << ' ';
        cout << endl << endl;
        
    }

    for (int i = 0; i < dg.Vcnt; ++i)
        cout << prim(dg, i) << endl;
    cout << kruskal(dg) << endl;
}

 

posted @ 2015-08-27 10:38  湛雷冲  阅读(614)  评论(0编辑  收藏  举报