• pku 1679 (次小生成树)


    题目大意】

    给出一个带权无向图,问其最小生成树是否唯一,若唯一输出其权值和,否则输出"Not Unique!".

    1.其实,在判断最小生成树是否是唯一的时候,用到了次小生成树的思想,求一棵次小生成树,最次小生成树的总权值等于最小生成树的权值,则不唯一;

    这里涉及到求次小生成树的问题,首先用prim 算法求一个最小生成树, 再做一次添边和删边的操作,添加一条最小生成树外的边,此时必在最小生成树上形成环,在删去环上权值最大的边,求出添删操作中差额最小值,若最小值为0,则不唯一,否则唯一;(这里我是这样做的,在pime算法求最小生成树的过程中,有一个增加生成树节点的操作,每增加一个节点,则求出该节点到生成树上每一个点的路径上的最大边)

    2.第二种判断方法,在pime算法过程中,若某个点i的D[i]被确定时,D[i]能够被2个或以上的点更新得到,那么MST显然不唯一。

    判断方法一:

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    int g[110][110],n,m,ans,d[110],pre[110];
    int max1[110][110],stack[110];
    bool flag[110];
    //max1[i][j]表示i 到j路径上最大边的值
    void prim()
    {
        memset(flag,false,sizeof(flag));
        flag[1]=0;
        for(int i=2;i<=n;i++)
        {
            pre[i]=1;
            d[i]=g[1][i];
        }
        d[1]=0;
        ans=0;
        int top=0;
        stack[top++]=1;//保存最小生成树上的节点
        for(int i=1;i<n;i++)
        {
            int tmp=INT_MAX,t=1;
            for(int j=2;j<=n;j++)
            {
                if(!flag[j]&&d[j]!=-1&&d[j]<tmp)
                    t=j,tmp=d[j];
            }
            flag[t]=true;
            ans+=tmp;
            for(int i=0;i<top;i++)//求出当前找到的节点到最小生长树上每一个点的路径上的最大边
                max1[stack[i]][t]=max1[t][stack[i]]=max(max1[pre[t]][stack[i]],tmp);
            stack[top++]=t;
            for(int j=1;j<=n;j++)
            {
                if(!flag[j]&&g[t][j]!=-1&&(g[t][j]<d[j]||d[j]==-1))
                {
                    d[j]=g[t][j];
                    pre[j]=t;//记录直接前驱
                }
            }
        }
    }
    int main()
    {
        int cas;
        int a,b,c;
        scanf("%d",&cas);
        while(cas--)
        {
            memset(g,-1,sizeof(g));
            scanf("%d %d",&n,&m);
            for(int i=0;i<m;i++)
            {
                scanf("%d %d %d",&a,&b,&c);
                g[a][b]=g[b][a]=c;
            }
            memset(max1,-1,sizeof(max1));
            prim();
            int min1=INT_MAX;
            for(int i=1;i<=n;i++)//枚举最小生成树外 的边
                for(int j=1;j<=n;j++)
                    if(i!=j&&i!=pre[j]&&j!=pre[i]&&g[i][j]>0)
                        min1=min(g[i][j]-max1[i][j],min1);
            if(min1) cout<<ans<<endl;
            else cout<<"Not Unique!"<<endl;
        }        
            return 0;
    }
    

    判断方法二:

    #include<cstdio>
    #include<cstdlib>
    #define N 110
    const int inf=10000000;
    
    int n,m,a[N][N],d[N],v[N],s,change[N];
    
    void init(){
        scanf("%d %d",&n,&m);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                a[i][j]=inf-1;
        for (int i=0;i<m;i++){
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            a[x][y]=a[y][x]=z;
        }
        for (int i=1;i<=n;i++)
            v[i]=0,d[i]=inf,change[i]=0;
        return;
    }
    
    bool solve(){
        s=0;
        d[1]=0;
        for (int t=0;t<n;t++){
            int min=inf,k=0;
            for (int i=1;i<=n;i++)
                if (!v[i]&&d[i]<min){
                    min=d[i];
                    k=i;
                }
            if (!k) break;
            v[k]=1;
            if (change[k]>=2) return 0;
            s+=min;
            for (int i=1;i<=n;i++)
                if (!v[i])
                    if (a[k][i]<d[i])d[i]=a[k][i],change[i]=1;
                    else if (a[k][i]==d[i])
                            change[i]++;
        }
        return 1;
    }
    int main(){
        int tests;
        scanf("%d",&tests);
        for (int i=0;i<tests;i++){
            init();
            if (solve()) printf("%d\n",s);
            else         printf("Not Unique!\n");
        }
    }
    

  • 相关阅读:
    FiddlerScript修改特定请求参数下的返回值
    nginx设置反向代理后,页面上的js css文件无法加载
    通过外网访问内网服务器
    linux下使用正确的用户名密码,本地无法连接mysql
    合并重叠时间段C#
    数据库一直显示为单用户,解决办法
    windows下使用tomcat部署网站
    数据库一直还原中,解决办法
    通过mdf ldf文件还原数据库
    知道css有个content属性吗?有什么作用?有什么应用?
  • 原文地址:https://www.cnblogs.com/nanke/p/2145226.html
Copyright © 2020-2023  润新知