初学Kruskal——Prime

来源:互联网 发布:阿里云 dns服务器地址 编辑:程序博客网 时间:2024/05/24 07:38

刚学了最小生成树,,,,做了这个题:NYOJ 布线问题 http://acm.nyist.net/JudgeOnline/problem.php?pid=38

布线问题

时间限制:1000 ms  |  内存限制:65535 KB
难度:4
描述
南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:
1、把所有的楼都供上电。
2、所用电线花费最少
输入
第一行是一个整数n表示有n组测试数据。(n<5)
每组测试数据的第一行是两个整数v,e.
v表示学校里楼的总个数(v<=500)
随后的e行里,每行有三个整数a,b,c表示a与b之间如果建铺设线路花费为c(c<=100)。(哪两栋楼间如果没有指明花费,则表示这两栋楼直接连通需要费用太大或者不可能连通)
随后的1行里,有v个整数,其中第i个数表示从第i号楼接线到外界供电设施所需要的费用。( 0<e<v*(v-1)/2 )
(楼的编号从1开始),由于安全问题,只能选择一个楼连接到外界供电设备。
数据保证至少存在一种方案满足要求。
输出
每组测试数据输出一个正整数,表示铺设满足校长要求的线路的最小花费。
样例输入
14 61 2 102 3 103 1 101 4 12 4 13 4 11 3 5 6
样例输出
4
这题思路就是找出最小生成树,,在加上与外界连得最小值就可以了。。。

找最小生成树有Kruskal和Prime两种算法。

个人觉得Kruskal和并查集的写法很像,,,区别只是并查集在查找过程中需要不断更新,,,而Kruskal需要在查找结束后重新定义父亲节点时加上这个点的权值。。。

确实,在写Kruskal的时候一定要注意题目中边的数目(边数 <= n * (n - 1) / 2),不要把数组开小了。(Kruskal与边数有关) 

而Prime与点数有关。。。

Kruskal AC代码:

 #include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#define PI 3.1415926using namespace std;typedef long long LL;int Q[125000];struct Node{    int m,n,d;    bool operator < (Node a)const    {        return d < a.d;    }} E[125000];int main(){//    freopen("in.txt","r",stdin);    int t;    scanf("%d",&t);    while(t --)    {        int n,m;        scanf("%d%d",&n,&m);        for(int i = 1; i <= n; i++)            Q[i] = i;        int a,b,w;        for(int i = 0; i < m; i++)        {            scanf("%d%d%d",&a,&b,&w);            E[i].m = a;            E[i].n = b;            E[i].d = w;        }        sort(E,E + m);        int Mx = 10000000;        for(int i = 1; i <= n; i++)        {            int x;            scanf("%d",&x);            Mx = min(Mx,x);        }        int num = 0,ans = 0;        for(int i = 0; i < m && num < n - 1; i ++)        {            int j,k;            for(j = E[i].m; Q[j] != j; j = Q[j])                Q[j] = Q[Q[j]];            for(k = E[i].n; Q[k] != k; k = Q[k])                Q[k] = Q[Q[k]];            if(j != k)            {                Q[k] = j;                ans += E[i].d;                num ++;            }        }        printf("%d\n",ans + Mx);    }    return 0;}        
另外一种写法:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#define PI 3.1415926using namespace std;typedef long long LL;int ans ,num;int Q[125000];struct Node{    int m,n,d;    bool operator < (Node a)const    {        return d < a.d;    }} E[125000];int Find(int x){    int r = x;    while(r != Q[r])r = Q[r];    /*****************    并查集还要加上:    int j = x;    while(Q[j] != r)    {        j = Q[j];        Q[j] = r;    }    ******************/    return r;}void MA(int x,int y,int w){    x = Find(x);    y =  Find(y);    if(x != y)    {        Q[x] = y;          ans += w;  // 并查集没        num ++;    // 有这些操作    }}int main(){//    freopen("in.txt","r",stdin);    int t;    scanf("%d",&t);    while(t --)    {        ans = 0;        int n,m;        scanf("%d%d",&n,&m);        for(int i = 1; i <= n; i++)            Q[i] = i;        int a,b,w;        for(int i = 0; i < m; i++)        {            scanf("%d%d%d",&a,&b,&w);            E[i].m = a;            E[i].n = b;            E[i].d = w;        }        sort(E,E + m);        int Mx = 10000000;        for(int i = 1; i <= n; i++)        {            int x;            scanf("%d",&x);            Mx = min(Mx,x);        }        num = 0;        for(int i = 0; i < m && num < n - 1; i ++)        {            MA(E[i].m,E[i].n,E[i].d);        }        printf("%d\n",ans + Mx);    }    return 0;}

Prime AC代码:

 #include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#define PI 3.1415926#define INF 0x3f3f3f3fusing namespace std;typedef long long LL;int vis[550],low[550];int Map[550][550];int n,m;int Prim(){    memset(vis,0,sizeof(vis));    vis[1] = 1;    int sum = 0;    for(int i = 1; i <= n; i++)    {        low[i] = Map[1][i];    }    int k;    for(int i = 2; i <= n; i++)    {        int tem = INF;        for(int j = 1; j <= n; j++)        {            if(!vis[j] && tem > low[j])            {                tem = low[j];                k = j;            }        }        if(tem == INF)break;        vis[k] = 1;        sum += tem;        for(int j = 1; j <= n; j++)        {            if(!vis[j] && low[j] > Map[k][j])                low[j] = Map[k][j];        }    }    return sum ;}int main(){//    freopen("in.txt","r",stdin);    int t;    scanf("%d",&t);    while(t --)    {        scanf("%d%d",&n,&m);        int a,b,w;        for(int i = 1; i <= n; i++)        {            for(int j = 1; j <= n; j++)                Map[j][i] = INF;        }        for(int i = 1; i <= n; i++)            Map[i][i] = 0;        for(int i = 0; i < m; i++)        {            scanf("%d%d%d",&a,&b,&w);            if(w < Map[a][b])    //  千万别忘了这个,因为这个还wa了一次             {                Map[a][b] = w;                Map[b][a] = w;            }        }        int Mx = INF;        for(int i = 1; i <= n; i++)        {            int x;            scanf("%d",&x);            Mx = min(Mx,x);        }        int ans = Mx;        ans += Prim();        printf("%d\n",ans);    }    return 0;}        




0 0
原创粉丝点击