Kruskal & Prim 最小生成树HDU1863 畅通工程

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863

题意:求构成一个连通图的最小代价,一看就是最小生成树。

思路:最小生成树版题。

想用use数组表示两个点是否用过,后来发现这样行不通,因为会忽略链接两个连通子图的边。

源码:

Kruskal:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

#include <vector>

using namespace std;

int const MAXN = 100+2;

int pa[MAXN],use[MAXN],ans,n,m,dot;

struct edge

{

    int s,e,val;

    void init(int a,int b,int c)

    {

        s = a; e = b; val = c;

    }

}d[MAXN*MAXN];

bool cmp(edge a,edge b)

{

    return a.val<b.val;

}

int fi(int a)

{

    if(a!=pa[a]) return fi(pa[a]);

    return a;

}

void init()

{

    for(int i=1; i<=m; i++) pa[i] = i;

    memset(use,0,sizeof(use));

    int s,e,val;

    for(int i=0; i<n; i++){

        scanf("%d%d%d",&s,&e,&val);

        d[i].init(s,e,val);

    }

    sort(d,d+n,cmp);

    ans = 0;

}

void Kruskal()

{

    dot = 1;

    for(int i=0; i<n; i++){

        int x = fi(d[i].s);

        int y = fi(d[i].e);

        if(x!=y){

            dot++;

            pa[x] = y;

            ans+=d[i].val;

        }

    }

}

void solve()

{

    if(dot!=m)    printf("?\n");

    else printf("%d\n",ans);

}

int main()

{

    while(scanf("%d%d",&n,&m)!=EOF && n){

        init();

        Kruskal();

        solve();

    }

    return 0;

}

Prim

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <iostream>

#include <queue>

using namespace std;

int const MAXN = 100+5;

int edge[MAXN][MAXN],use[MAXN],tot,ans,n,m;

struct D

{

    int mark,val;

}low[MAXN];

void init()

{

    memset(use,0,sizeof(use));

    memset(edge,-1,sizeof(edge));

    int s,e,val;

    while(n--){

        scanf("%d%d%d",&s,&e,&val);

        edge[e][s] = edge[s][e] = val;

    }

    tot = 1;

    ans = 0;

}

int fi()

{

    int flag = 1;

    int pos = 1;

    for(int i=1; i<=m; i++)

    {

        if(use[i]==0 && low[i].val!=-1 && (low[i].val<=low[pos].val || low[pos].val==-1)){

            flag = 0;

            pos = i;

        }

    }

    if(flag)    return -1;

    else    return pos;

}

void Prim()

{

    use[1] = 1;

    int pos = 1;

    for(int i=1; i<=m; i++){///初始化

        low[i].mark = 1;

        low[i].val = edge[1][i];

    }

    pos = fi();

    tot++;

    ans += low[pos].val;

    use[pos] = 1;

    while(1){

        for(int j=1; j<=m; j++){

            if(edge[pos][j]!=-1 && use[j]==0 && ((edge[pos][j]<low[j].val) || low[j].val==-1)){

                low[j].mark = pos;

                low[j].val = edge[pos][j];

            }

        }

        pos = fi();

        if(pos != -1){

            ans += low[pos].val;

            use[pos] = 1;

            tot++;

        }

        else break;

    }

}

void solve()

{

    if(tot==m)  printf("%d\n",ans);

    else    printf("?\n");

}

int main()

{

    while(scanf("%d%d",&n,&m)!=EOF && n){

        init();

        Prim();

        solve();

    }

    return 0;

}

 

错误版:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

#include <vector>

using namespace std;

int const MAXN = 100+2;

int pa[MAXN],use[MAXN],ans,n,m,dot;

struct edge

{

    int s,e,val;

    void init(int a,int b,int c)

    {

        s = a; e = b; val = c;

    }

}d[MAXN*MAXN];

bool cmp(edge a,edge b)

{

    return a.val<b.val;

}

int fi(int a)

{

    if(a!=pa[a]) return fi(pa[a]);

    return a;

}

void init()

{

    for(int i=1; i<=m; i++) pa[i] = i;

    memset(use,0,sizeof(use));

    int s,e,val;

    for(int i=0; i<n; i++){

        scanf("%d%d%d",&s,&e,&val);

        d[i].init(s,e,val);

    }

    sort(d,d+n,cmp);

    ans = 0;

}

void Kruskal()

{

//    use[d[0].s] = 1;

//    use[d[0].e] = 1;

//    ans += d[0].val;

//    dot = 1;

    for(int i=0; i<n; i++){

        if(use[d[i].s]==1 && use[d[i].e]==1)

            continue;

        use[d[i].s] = 1;

        use[d[i].e] = 1;

//        int x = fi(d[i].s);

//        int y = fi(d[i].e);

//        printf("i = %d,x = %d,y = %d\n",i,x,y);

//        if(x!=y){

//            dot++;

//            pa[x] = y;

//            ans+=d[i].val;

//        }

        ans += d[i].val;

    }

}

void solve()

{

    int flag = 0;

    for(int i=1; i<=n; i++){

        if(use[i]==0){

            flag = 1; break;

        }

    }

    if(flag)    printf("?\n");

    else    printf("%d\n",ans);

 

}

int main()

{

    while(scanf("%d%d",&n,&m)!=EOF && n){

        init();

        Kruskal();

        solve();

    }

    return 0;

}

 

你可能感兴趣的:(自我训练)