LouZhang

导航

poj1679,次小生成树的学习

昨天总结MST的模板,也写的差不多了吧

总之两种方法,kruskal和prim

麻烦的可能就是生成MST的唯一性的判定

原理很简单,先找MST,然后枚举MST上每条边,方法是删除该边再找MST,如果能找到MST并且权值等于第一次找到的,就不唯一了

 

http://poj.org/problem?id=1679

# include <iostream>
# include <cstdio>
# include <algorithm>
# include <cstring>
using namespace std;


//先求出最小生成树,然后删除这棵树上的每条边求MST,求的时候要判断是否是MST
struct edge{
    int u, v, w, f;
    friend bool operator < (const edge &a, const edge &b){
        return a.w < b.w;
    }
}e[100 * 100 + 10];
int pre[110];
int n, m;
int find(int x){
    int s;
    for(s = x; pre[s] >= 0; s = pre[s]);
    while(s != x){
        int t = pre[x];
        pre[x] = s;
        x = t;
    }
    return s;
}
void Union(int x, int y){
    int u = find(x);
    int v = find(y);
    if(u == v) return;//如果在同一棵树上
    if(pre[u] > pre[v]){
        pre[u] += pre[v];
        pre[v] = u;
    }else{
        pre[v] += pre[u];
        pre[u] = v;
    }
}
int kruskal(int f){
    int w = 0;
    int num = 0;
    memset(pre, -1, sizeof pre);
    for(int i = 0; i < m; i ++){
        if(e[i].f == 2) continue;
        int u = e[i].u;
        int v = e[i].v;
        if(find(u) != find(v)){
            w += e[i].w;
            if(f)e[i].f = 1;
            num ++;
            Union(u, v);
        }
        if(num >= n - 1)
          break;
    }
    if(num == n-1)
    return w;
    else return -1;//说明没有找到MST
}
int main(){
    int tcase;
    scanf("%d", &tcase);
    while(tcase --){
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i ++){
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
            e[i].f = 0;
        }
        sort(e, e + m);
        int w = kruskal(1);
        int flag = 0;
        for(int i = 0; i < m; i ++){
            if(e[i].f == 0)continue;
            e[i].f ++;
            int tmp = kruskal(0);
            e[i].f --;
            //printf("%d ---\n", tmp);
            if(tmp != -1 && tmp == w){
                flag = 1;
                break;
            }
        }
        if(flag)
          puts("Not Unique!");
        else
          printf("%d\n", w);
    }
    return 0;
}


/*
//牛人做法,拿来当模板用
int const INF=1000000000;
int const maxn=105;
int mark[maxn],map[maxn][maxn],mst[maxn];
int n,m;
void prim(){
    int i,j,k,ans=0,min,v,flag=0;
    for (i=1;i<=n;i++){
        mark[i]=0;
        mst[i]=map[1][i];
    }
    mark[1]=1;
    for (i=1;i<n;i++){
        min=INF;
        for (j=1;j<=n;j++){
            if (!mark[j] && mst[j]<min){
                min=mst[j];
                v=j;
            }
        }
        k=0;
        //------------------------------
        //如果要选的点到已选的点,还有一条边权值相同,就 NO 了
        for (j=1;j<=n;j++){
            if (mark[j] && min==map[v][j])k++;
        }
        if (k>1){flag=1;break;}
        //------------------------------
        ans+=min;
        mark[v]=1;
        for (j=1;j<=n;j++){
            if (!mark[j] && map[v][j]<mst[j])mst[j]=map[v][j];
        }
    }
    if (flag)cout<<"Not Unique!"<<endl;
    else cout<<ans<<endl;
}
int main()
{
    int cas,i,j,p,q,w;
    cin>>cas;
    while (cas--)
    {
        cin>>n>>m;
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                map[i][j]=INF;
        while (m--)
        {
            cin>>p>>q>>w;
            map[q][p]=map[p][q]=w;
        }
        prim();
    }
    return 0;
}
*/

posted on 2012-08-02 10:08  louzhang_swk  阅读(178)  评论(0编辑  收藏  举报