最小生成树

来源:互联网 发布:开源人工智能语音系统 编辑:程序博客网 时间:2024/06/03 18:17

Problem Description
有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的。现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市。

Input
输入包含多组数据,格式如下。
第一行包括两个整数n m,代表城市个数和可以修建的公路个数。(n <= 100, m <=10000)
剩下m行每行3个正整数a b c,代表城市a 和城市b之间可以修建一条公路,代价为c。

Output
每组输出占一行,仅输出最小花费。
Example Input
3 2
1 2 1
1 3 1
1 0
Example Output
2
0

快排
并查集
结构体

#include <iostream>#include <cstdio>#include <cstring>using namespace std;struct node{    int a,b,c;}e[10010];//用结构体来存城市a,城市b,代价cint f[110];//并查集。存每个顶点各自相应的bossvoid quicksort(int left, int right){    int i, j;    if(left > right)    {        return;    }    i = left;    j = right;    while(i != j)    {        while(e[j].c >= e[left].c && i<j)//e[left].c(最左端)作为基元素        {            j--;        }        while(e[i].c <= e[left].c && i<j)        {            i++;        }        if(i<j)        {            swap(e[i],e[j]);//交换整体        }    }    swap(e[left],e[i]);//当i=j时,交换e[i]和最左端的基元素(e[left])    quicksort(left,i-1);    quicksort(i+1,right);    return;}int getf(int v){    if(f[v] == v)        return v;    else    {        f[v] = getf(f[v]);//递归求大boss        return f[v];    }}int merge(int v, int u)//并查集作用:看两个顶点是否已连通:即看各自的boss是否相同{    int t1,t2;    t1 = getf(v);    t2 = getf(u);//找v和u顶点的大boss    if(t1!=t2)//各自分别的大boss不相同,就是之前不连通    {        f[t2] = t1;//两个法则:靠左原则+擒贼先擒王        //把u顶点归顺v顶点。所以把v顶点的boss t2归顺t1。        //所以把t2的boss归顺t1即可(擒贼先擒王)        return 1;    }    return 0;}int main(){    int n, m, i;    int sum, count;//sum为代价之和,count是边数(公路数)    while(cin>>n>>m)    {        sum = 0;        count = 0;        memset(f, 0, sizeof(f));        for(i = 1; i <= m; i++)        {            cin>>e[i].a>>e[i].b>>e[i].c;        }        quicksort(1,m);//使用快排,对n个c降序排列        for(i = 1; i <= n; i++)//对n个城市        {            f[i] = i;//对n个城市(n个顶点)初始化,每个人是自己的boss        }        for(i = 1; i <= m; i++)        {            if(merge(e[i].a,e[i].b))//a。b顶点在这之前不通            {                count++;                sum += e[i].c;            }            if(count == n-1)//边数等于顶点数-1            {                break;            }        }        cout<<sum<<endl;    }    return 0;}

dijsktra算法,类似求最短路径

#include <iostream>#include <cstring>using namespace std;#define INF 0x3f3f3fint n;int map[110][110];int visit[110];void prime(){    int i, j, min, sum = 0;    int next;    int dis[110];    for(i = 1; i <= n; i++)    {        dis[i] = map[1][i];//假设把1顶点当做源点    }    visit[1] = 1;    for(i = 2; i <= n; i++)//1到n编号, 操作n-1个顶点    {        min = INF;        next = -1;        for(j = 1; j <= n; j++)//找出距离1顶点路径最小的点来赋给next        {            if(visit[j] != 1 && dis[j] < min)            {                min = dis[j];                next = j;            }        }        if(next == -1)            break;        visit[next] = 1;        sum += min;//最短路径之和        for(j = 1; j <= n; j++)//根据新加的那个next点来"松弛"        {            if(visit[j] != 1 && map[next][j] < dis[j])//最小生成树与最短路径的区别是:            //最小生成树加进来的next点成为树里的节点,所以“松弛”其他点到“树”的最短距离即可            //最短路径:“松弛”的仍是到源点的距离            {                dis[j] = map[next][j];            }        }    }    cout<<sum<<endl;}int main(){    int i, a, b, c, m;    while(cin>>n>>m)    {        memset(map, INF, sizeof(map));        memset(visit, 0, sizeof(visit));        for(i = 0; i < m; i++)        {            cin>>a>>b>>c;            if(c < map[a][b])            {                map[a][b] = map[b][a] = c;//无向图            }        }        prime();    }    return 0;}
原创粉丝点击