稀疏图(邻接链表),并查集,最短路径(Dijkstra,spfa),最小生成树(kruskal,prim)

#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 node{
    int v;
    weightType val;
    node* next;
    node(int v = -1, weightType val = NOEDGE, node* next = NULL) :v(v), val(val), next(next){}
};
typedef node* link;
struct sparseGraph{
    int Vcnt, Ecnt;    //顶点数,边数
    bool dg;    //有向图 ?
    vector<link> adj;    //邻接链表
    sparseGraph(int v, bool dg = false) :adj(v), Vcnt(v), Ecnt(0), dg(dg){
        adj.assign(v, NULL);
    }
    void insert(edge e){
        int v = e.v, w = e.w, val = e.val;
        adj[v] = new node(w, val, adj[v]);
        if (!dg) adj[w] = new node(v, val, adj[w]);
        ++Ecnt;
    }
    void show(){
        printf("Vcnt = %d, Ecnt = %d, Directed : %d\n", Vcnt, Ecnt, dg);
        link p = NULL;
        for (int i = 0; i < Vcnt; ++i){
            p = adj[i];
            printf("%d: ", i);
            while (p){
                cout << p->v << ‘,‘;
                cout << p->val;
                p = p->next;
                if (p) printf(" ");
            }
            printf("\n");
        }
    }
};

//用于Dijkstra,prim中的队列优化,可选
struct keyValue{
    int key, value;
    keyValue(int key, int value) :key(key), value(value){}
};
template<class T>
struct myGreater{
    bool operator() (const T& x, const T& y) const{ return x.key > y.key; }
};

//Dijkstra算法
weightType dDijkstra[N];    //存放所有顶点到 s 的最短路径距离
int pDijkstra[N];        //pDijkstra[i],路径存在时,存放节点 i 的前驱,不存在时,-1
void Dijkstra(const sparseGraph &sg, int s)
{
    bool visit[N];
    for (int i = 0; i < sg.Vcnt; ++i){
        visit[i] = false;
        dDijkstra[i] = NOEDGE;
        pDijkstra[i] = -1;
    }
    link p = sg.adj[s];
    while (p){
        dDijkstra[p->v] = p->val;
        pDijkstra[p->v] = s;
        p = p->next;
    }
    visit[s] = true; dDijkstra[s] = 0;
    for (int i = 0; i < sg.Vcnt - 1; ++i){
        int min = NOEDGE;
        int v = 0;
        /*优先队列代替
        priority_queue < keyValue, vector<keyValue>, myGreater<keyValue> > qq;
        for (int j = 0; j < sg.Vcnt; ++j)
            if (!visit[j]) qq.push(keyValue(dDijkstra[j], j));
        keyValue u = qq.top();
        v = u.value; min = dDijkstra[v];
        */
        for (int j = 0; j < sg.Vcnt; ++j){
            if (!visit[j] && dDijkstra[j] < min){
                v = j; min = dDijkstra[j];
            }
        }
        visit[v] = true;
        p = sg.adj[v];
        while (p){
            if (!visit[p->v] && p->val + min < dDijkstra[p->v]){
                dDijkstra[p->v] = p->val + min;
                pDijkstra[p->v] = v;
            }
            p = p->next;
        }
    }
}

//最短路径 SPFA算法
weightType dSpfa[N];
int pSpfa[N];
void spfa(const sparseGraph& sg, int s)
{
    bool visit[N];
    for (int i = 0; i < sg.Vcnt; ++i){
        visit[i] = false;
        dSpfa[i] = NOEDGE;
        pSpfa[i] = -1;
    }
    dSpfa[s] = 0;
    int u;
    link p = NULL;
    queue<int> q;
    q.push(s);
    while (!q.empty()){
        u = q.front(); q.pop(); visit[u] = true;
        p = sg.adj[u];
        while (p){
            int v = p->v;
            if (dSpfa[u] + p->val < dSpfa[v]){
                dSpfa[v] = dSpfa[u] + p->val;
                pSpfa[v] = u;
                if (!visit[v]) q.push(v);
            }
            p = p->next;
        }
    }
}
//最小生成树 prim
weightType dPrim[N];    //存放所有顶点到 s 的最短路径距离
weightType prim(const sparseGraph &sg, int s)
{
    weightType sum = 0;
    bool visit[N];
    for (int i = 0; i < sg.Vcnt; ++i){
        visit[i] = false;
        dPrim[i] = NOEDGE;
    }
    link p = sg.adj[s];
    while (p){
        dPrim[p->v] = p->val;
        p = p->next;
    }
    visit[s] = true; dPrim[s] = 0;
    for (int i = 0; i < sg.Vcnt - 1; ++i){
        weightType min = NOEDGE;
        int v = 0;
        for (int j = 0; j < sg.Vcnt; ++j){
            if (!visit[j] && dPrim[j] < min){
                v = j; min = dPrim[j];
            }
        }
        sum += min;
        visit[v] = true;
        p = sg.adj[v];
        while (p){
            if (!visit[p->v] && p->val < dPrim[p->v]){
                dPrim[p->v] = p->val;
            }
            p = p->next;
        }
    }
    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 sparseGraph &sg)
{
    weightType sum = 0;
    vector<edge> ve;        //取图的所有边,并排序
    edge e;
    link p = NULL;
    for (int i = 0; i < sg.Vcnt; ++i){
        p = sg.adj[i];
        e.v = i;
        while (p){
            e.w = p->v;
            e.val = p->val;
            ve.push_back(e);
            p = p->next;
        }
    }
    sort(ve.begin(), ve.end(), kruskalComp);
    for (int i = 0; i < sg.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;
    sparseGraph sg(n,true);
    while (m--){
        cin >> v >> w >> val;
        sg.insert(edge(v-1, w-1, val));
    }
    sg.show();
    cout << endl;
    for (int i = 0; i < sg.Vcnt; ++i){
        spfa(sg, i);
        Dijkstra(sg, i);
        for (int i = 0; i < sg.Vcnt; ++i)
            cout << dSpfa[i] << ‘ ‘;
        cout << endl;
        for (int i = 0; i < sg.Vcnt; ++i)
            cout << dDijkstra[i] << ‘ ‘;
        cout << endl;

        for (int i = 0; i < sg.Vcnt; ++i)
            cout << pSpfa[i] << ‘ ‘;
        cout << endl;
        for (int i = 0; i < sg.Vcnt; ++i)
            cout << pDijkstra[i] << ‘ ‘;
        cout << endl << endl;
    }
    for (int i = 0; i < sg.Vcnt; ++i)
        cout << prim(sg, i) << endl;
    cout << kruskal(sg) << endl;
}
时间: 2024-11-08 05:46:59

稀疏图(邻接链表),并查集,最短路径(Dijkstra,spfa),最小生成树(kruskal,prim)的相关文章

赛码&quot;BestCoder&quot;杯中国大学生程序设计冠军赛1009——邻接表+并查集——Exploration

Problem Description Miceren likes exploration and he found a huge labyrinth underground! This labyrinth has N caves and some tunnels connecting some pairs of caves. There are two types of tunnel, one type of them can be passed in only one direction a

最小生成树 并查集 最短路径

#include<stdio.h> #include<stdlib.h> struct edge{ int u; int v; int w;//为了方便排序这里穿件一个结构体来存储边的关系 }e[10]; int n,m; int f[10]={0},sum=0,count=0;//并查集需要得到的一些变量 //f数组大小根据实际情况来设置,要比n的最大值大1 //排序 int cmp(const void *a,const void *b) { return (((struct

POJ3723(邻接表+并查集+Kruskal)

题目链接:点击打开链接 解题思路: 根据相互之间的关系,可以转化一个无向图中最大权森林的问题.也就是把边权取反,然后用最小生成树求解. 本题用邻接表存储,Kruskal求最小生成树. 完整代码: #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <set> #include &l

hdu 1272 判断所给的图是不是生成树 (并查集)

判断所给的图是不是生成树,如果有重边就不是,如果没重边但连通分量大于1也不是 find函数 用之前那个递归的写的话 会无限栈溢出 Orz 栈溢出的话 就加上这一串 #pragma comment(linker, "/STACK:1024000000,1024000000") Sample Input6 8 5 3 5 2 6 45 6 0 0 8 1 7 3 6 2 8 9 7 57 4 7 8 7 6 0 0 3 8 6 8 6 45 3 5 6 5 2 0 0 -1 -1 Samp

图的邻接表(广度优先遍历,深度优先遍历,最小生成树(Kruskal算法))

main.h: #include <iostream> #include <queue> #define DefaultSize 10 #define maxWeight -1 using namespace std; template<typename T,typename E> struct Edge { int dest; E cost; Edge<T,E> *link; Edge(int d=0,int c=0):dest(d),cost(c),li

hdoj-1869 六度分离【最短路径--dijkstra&amp;&amp;spfa&amp;&amp;floyd】

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1869 解题思路: 转化成最短路径问题,如果两人认识,把两者之间距离看成1      如果任意两人之间隔着7个人及其以上 (即距离>7)   则不满足六度分离 spfa: #include<cstdio> #include<cstring> #include<queue> #define INF 0x3f3f3f3f #define MAXN 100+10//点数 #def

并查集初步题目(2)

vector和邻接表 并查集的一个很风骚的技巧 一. vector数组操作 包含vector头文件 声明:vector<type> name; 方法: 加入一个元素至最后:vec.push_back(val); 清空数组中的所有元素:vec.clear(); 访问其中元素:vec.at(i); vector中元素的个数:vec.size(); 指定当前vector内元素个数:vec.resize(n); 会保留前n个元素. 邻接表是一种储存图的方式,通常使用链表或者vector可变长数组实现.

习题:过路费(kruskal+并查集+LCA)

过路费  [问题描述]在某个遥远的国家里,有 n 个城市.编号为 1,2,3,…,n.这个国家的政府修 建了 m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市 T 需 要收取的过路费为所经过城市之间道路长度的最大值.如:A 到 B 长度为 2,B 到 C 长度为 3,那么开车从 A 经过 B 到 C 需要上交的过路费为 3. 佳佳是个做生意的人,需要经常开车从任意一个城市到另外一个城市,因此 他需要频繁地上交过路费,由于忙于做生意,所以他无时间来寻找交过路费最低 的行驶路线.然

数据结构之并查集

并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等. 使用并查集时,首先会存在一组不相交的动态集合 S={S1,S2,?,Sk},一般都会使用一个整数表示集合中的一个元素. 每个集合可能包含一个或多个元素,并选出集合中的某个元素作为代表.每个集合中具体包含了哪些元素是不关心的,具体选择哪个元素作为

并查集(Disjoint Set)

http://www.cnblogs.com/cyjb/p/UnionFindSets.html http://blog.csdn.net/dm_vincent/article/details/7655764 http://blog.csdn.net/dm_vincent/article/details/7769159 并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的 Kruskal 算法和