PKU-#1679 The Unique MST(次小生成树)

        题目大意:给出n个点,m条边的图。判断最小生成树是否唯一。

        解题思路:就是一个次小生成树的问题,求次小生成树与最小生成树的权值是否一致即可。做法有两种:一是Prim进行判断,方法:求一次最小生成树,将生成树的边标记,并记录MST值。然后枚举删边。枚举除生成树外的其它边,更新一个最小的生成树的权值。最后比较这两个权值时候相等。相等则说明不唯一,否则唯一,输出权值。二是Kruskal算法,做法是:求一次最小生成树,标记生成树的边,然后枚举这些边,除枚举边外其它边求一次最小生成树,看权值是否相等,相等则说明不唯一。两种解法详见code。

        题目来源:http://poj.org/problem?id=1679

      Prim  code:

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

const int MAXN = 100+10;
const int inf = 99999999;
int t,n,m,x,y,w;
int g[MAXN][MAXN],dist[MAXN],vis[MAXN],path[MAXN][MAXN],pre[MAXN];
bool used[MAXN][MAXN];

int prim(){
    int ans=0;
    memset(vis,0,sizeof(vis));
    memset(path,0,sizeof(path));
    memset(used,0,sizeof(used));
    vis[1]=1;
    for(int i=1;i<=n;++i){
        dist[i]=g[1][i];
        pre[i]=1;
    }
    for(int i=1;i<n;++i){
        int u=-1;
        for(int j=1;j<=n;++j)
            if(!vis[j] && (u==-1 || dist[j]<dist[u])) u=j;
        used[u][pre[u]]=used[pre[u]][u]=true;
        ans+=g[pre[u]][u];
        vis[u]=1;
        for(int k=1;k<=n;++k){
            if(vis[k] && k!=u)
                path[u][k]=path[k][u]=max(path[k][pre[u]],dist[u]);
            if(!vis[k] && dist[k]>g[u][k]){
                dist[k]=g[u][k];
                pre[k]=u;
            }
        }
    }
    return ans;
}

int main(){
    //freopen("input.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j){
                if(i==j) g[i][j]=0;
                else g[i][j]=inf;
            }
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&x,&y,&w);
            g[x][y]=w;
        }
        int mst=prim();
        int ans=inf;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(i!=j && !used[i][j])
                    ans=min(ans,mst+g[i][j]-path[i][j]); //次小生成树
        if(ans==mst) printf("Not Unique!\n");
        else printf("%d\n",mst);
    }
    return 0;
}

      Kruskal  code:终于还是A了,找了好几个小时都没有找到错误的,最后换交C++,一下就A了,还是很纠结这两个怎么选择呀!

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

const int MAXN = 100+10;
int t,n,m;
int p[MAXN];

struct node{
    int x,y,w;
    int flag;
}g[MAXN*MAXN];

int cmp(node a,node b){return a.w<b.w;}

int find(int x){return p[x]==x ? x : p[x]=find(p[x]);}

int Kruskal(int tmp){
    int ans=0,cnt=1;
    for(int i=0;i<=n;++i) p[i]=i;
    sort(g,g+m,cmp);
    for(int i=0;i<m;++i){
        if(i==tmp) continue; //如果是生成树的边则跳过,这里求最小生成树是传m进来,因此巧妙避开了计算
        int x=find(g[i].x);
        int y=find(g[i].y);
        if(x!=y){
            if(m==tmp) g[i].flag=1; //如果是求最小生成树,则需要标记生成树的边
            p[x]=y;
            ans+=g[i].w;
            cnt++;
        }
    }
    if(cnt!=n) return -1; //看是否存在孤立的点
    else return ans;
}

int main(){
    //freopen("input.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&g[i].x,&g[i].y,&g[i].w);
            g[i].flag=0; //初始化都标记为0
        }
        int mst=Kruskal(m);
        int flag=0;
        for(int i=0;i<m;++i){
            if(g[i].flag==0) continue; //如果不是生成树的边则跳过
            int ans=Kruskal(i);
            if(mst==ans){ //求次小生成树是否和最小生成树相等
                flag=1;
                break;
            }
        }
        if(flag) printf("Not Unique!\n");
        else printf("%d\n",mst);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值