美文网首页
判断最小生成树是否唯一 POJ --- 1679

判断最小生成树是否唯一 POJ --- 1679

作者: Anxdada | 来源:发表于2017-04-03 13:35 被阅读0次

    网上两种算法对应都有:
    题目链接

    prim算法判最小生成树是否唯一

    下面是这道题的AC代码:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #define CLR(x) memset(x,0,sizeof(x))
    using namespace std;
    const int maxn=105;
    const int inf=1e9;
    int cas=1;
    int n,m;
    int mapp[maxn][maxn],vis[maxn],dis[maxn];
    void prim(int u)
    {
        CLR(vis);
        int flag=0,sum=0;
        for(int i=1;i<=n;i++)
            dis[i]=mapp[u][i];
        vis[u]=1;
        for(int i=1;i<=n;i++){
            int minn=inf;
            int v=-1;
            for(int j=1;j<=n;j++){
                if(!vis[j] && minn>dis[j]){
                    v = j;
                    minn = dis[j];
                }
            }
            if(v!=-1){   //如果v=-1了,说明这个图已经连通了,不用再判断下去了,当然也可以直接break掉,一样的.
                //printf("%d %d\n",v,minn);
                int ans=0;   //记录相同权值的边有几条,把图画出来就懂的起了!!!
                for(int j=1;j<=n;j++){
                    if(vis[j] && mapp[v][j] == minn)   //这一步处理的非常好.
                        ans++;
                }
                if(ans>1){    //如果大于1,说明用其他路也能达到该点,所以树就不唯一了,所以可以直接break了.
                    flag=1;
                    break;
                }
                sum+=minn;
                vis[v]=1;
                for(int j=1;j<=n;j++){
                    if(!vis[j] && dis[j] > mapp[v][j])
                        dis[j] = mapp[v][j];
                }
            }
        }
        if(flag)
            printf("Not Unique!\n");
        else
            printf("%d\n",sum);
    }
    int main()
    {
        int t;
        cin >> t;
        while(t--){
            cin >> n >> m;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    if(i==j) mapp[i][j]=0;
                    else mapp[i][j]=inf;
                }
            }
            for(int i=0;i<m;i++){
                int u,v,w;
                cin >> u >> v >> w;
                mapp[u][v] = mapp[v][u] = w;
            }
            prim(1);   //从点 1 开始找.
        }
    }
    

    kruskal的算法,再用这个算法时有一点要特别注意,否则会一直WA,就是在进行删边操作时,注意删完或需要判断这个图是否是一个树!!!,如果不是的话返回-1或最大值,不要返回sum值,因为删去边后没有树的话,则最小生成树还是唯一的!!!
    AC代码:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<functional>
    #include<vector>
    #include<stack>
    #include<map>
    #include<cstdlib>
    #define CLR(x) memset(x,0,sizeof(x))
    #define ll long long int
    #define PI acos(-1.0)
    #define db double
    #define mod 1000000007
    using namespace std;
    const int maxn = 1e5+5;
    int pre[105];
    int n,m;
    vector<int>used;
    struct node{ int u,v,w;} s[maxn];
    void init(){ for(int i=0;i<=n;i++) pre[i]=i; }
    int Find(int x){ return pre[x]==x?x:pre[x]=Find(pre[x]); }
    bool cmp(node a,node b){ return a.w<b.w; }
    int kruskal(int flag)
    {
        int num=0;
        int sum=0;
        for(int i=0;i<m;i++){
            if(i==flag) continue;
            int u=Find(s[i].u);
            int v=Find(s[i].v);
            if( u != v){
                pre[v]=u;
                sum+=s[i].w;
                num++;
                if(flag==-1)
                    used.push_back(i);
            }
            if(num==n-1)
                break;
        }
        int cnt=0;    //一定判断一下树是否联通!!!
        for(int i=1;i<=n;i++){
            if(pre[i]==i)
                cnt++;
        }
        if(cnt>1)
            return -1;
        return sum;
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            CLR(s);
            scanf("%d %d",&n,&m);
            init();
            used.clear();     //不要忘了清空!!!
            for(int i=0;i<m;i++){
                scanf("%d %d %d",&s[i].u,&s[i].v,&s[i].w);
            }
            sort(s,s+m,cmp);
            int ans=kruskal(-1);
            int flag=0;
            for(int i=0;i<used.size();i++){
                init();
                int p=0;
                p=kruskal(used[i]);
                if(p==ans){
                    flag=1;
                    break;
                }
            }
            if(flag)
                printf("Not Unique!\n");
            else
                printf("%d\n",ans);
        }
    }
    
    

    相关文章

      网友评论

          本文标题:判断最小生成树是否唯一 POJ --- 1679

          本文链接:https://www.haomeiwen.com/subject/npnnottx.html