poj 1679

       这是一道求次小生成树的题目。

       首先,介绍一下什么是次小生成树。设T是无向连通图G的最小生成树,对于另一棵生成树T1(T1不等于T),如果不存在T2(T2不等于T),满足T2的权值之和小于T1的条件,那么T1称为次小生成树。从权值之和的角度看,次小生成树的权值可能大于最小生成树,也可能等于最小生成树。顺便提一下,如果无向连通图G的每条边权值均不相等,那么最小生成树唯一,也就是说,最小生成树的权值之和唯一。(证明,请参考《ACM—ICPC程序设计系列 图论及应用》(哈尔滨工业大学出版社)P39)

       了解了这些,就可以明白为什么是求次小生成树了,求出次小生成树的权值,与最小生成树的权值相比较,如果不相等则唯一,否则就不唯一。

       其次介绍一下求次小生成树的思路。

       最朴素的想法就是在图G中,删除一条最小生成树的边,然后再求最小生成树,如此循环处理,此时对于原图来说,次小生成树一定存在其中,并且是其中权值之和最小的那棵。

       还有一种思路,在求最小生成树时,先记录下任意两点间的最大权值的值,然后枚举属于图G但不属于最小生成树T的边,此时枚举的边正好与最小生成树中的部分边构成一个环,去除环中除了枚举的边之外权值最大的边,如此循环处理,次小生成树一定存在其中,并且是其中权值之和最小的那棵。那么,如何求树两点之间的最大权值呢?首先需要记录每个集合中的顶点标号,每次添加到最小生成树上的边的权值,都是这两个集合间的点之间的最大权值。在我的代码里,记录每个集合中点的方法,借用了链式前向星中存边的方法。(更具体的,请参考《ACM—ICPC程序设计系列 图论及应用》(哈尔滨工业大学出版社)P47)

        最后,说一些题外话。从交题之后的时间上来看,两种思路耗时一样多,不知为何。此外,写代码时忘记写并查集中的合并操作,导致提交N次都TLE,让我郁闷了好几天,直到今天,才被我偶然发现。出现这个问题,真是令人伤脑筋。此外,通过复制粘贴的方式写那些差不多的代码,也经常由于一些小的错误改半天,所以,下次写代码越是心急,越不能复制粘贴代码,因为急的时候根本不愿仔细看复制来的代码中需要修改的地方,很多地方可能没改到,那样更容易错,有时错误更隐蔽。


代码(C++):

方法1:

#include <cstdlib>
#include <iostream>
#include <algorithm>

#define MAX 103
using namespace std;

struct edge{
    int u;
    int v;
    int w;   
};

edge array[MAX*MAX];
int fa[MAX],n,m;
bool tag[MAX*MAX]; 

bool cmp(edge a,edge b)
{
    if(a.w!=b.w) return a.w<b.w;
    if(a.u!=b.u) return a.u<b.u;
    return a.v<b.v; 
}

int find(int a)
{
    if(fa[a]!=a) fa[a]=find(fa[a]);
    return fa[a];
}

int kruskal(int p)                 //amount记录生成树的边的条数 ,mstw表示去除标号为m的最小生成树的权值之和
{
    int i,amount=0,mstw=0,fu,fv;
    for(i=0;i<m;i++)
    {
       if(i==p) continue;             
       fu=find(array[i].u);
       fv=find(array[i].v); 
       if(fu==fv) continue;            
            
       fa[fu]=fv;       
       mstw+=array[i].w;
       amount++;           
       if(amount==n-1) break;            
    }
    if(i==m) return -1;                  // 如果不存在mst,则返回-1 
    else return mstw;
}

int kruskal()                 //amount记录生成树的边的条数 ,mstw表示去除标号为m的最小生成树的权值之和
{
    int i,amount=0,mstw=0,fu,fv;
    for(i=0;i<m;i++)
    {                 
       fu=find(array[i].u);
       fv=find(array[i].v); 
       if(fu==fv) continue;            
            
       fa[fu]=fv;       
       mstw+=array[i].w;
       tag[i]=true;
       amount++;           
       if(amount==n-1) break;            
    }
    return mstw;
}

int main(int argc, char *argv[]) 
{
    int i,j,k,t,u,v,w,ans,sec_mstw; //sec_mstw表示次小生成树的权值之和
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(i=0;i<m;i++)
        {
            scanf("%d %d %d",&u,&v,&w);
            array[i].u=u;
            array[i].v=v;
            array[i].w=w;           
        }        
        sort(array,array+m,cmp);
        
        for(i=0;i<=n;i++) fa[i]=i;
        memset(tag,false,sizeof(tag));
        ans=kruskal();
        
        for(i=0;i<m;i++)
        {             
           if(tag[i])
           {
               for(j=0;j<=n;j++) fa[j]=j;                    
               sec_mstw=kruskal(i);
               if(sec_mstw==ans) break;
           } 
        }                       
               
        if(i<m) printf("Not Unique!\n");
        else printf("%d\n",ans);
    }
    system("PAUSE");
    return EXIT_SUCCESS;
}

方法2:

#include <cstdlib>
#include <iostream>
#include <algorithm>

#define MAX 103
#define INF 99999999

using namespace std;

struct edge{
    int u;
    int v;
    int w;   
};

edge array[MAX*MAX];
int fa[MAX],head[MAX],next[MAX],end[MAX],length[MAX][MAX];
bool tag[MAX*MAX]; 

bool cmp(edge a,edge b)
{
    if(a.w!=b.w) return a.w<b.w;
    if(a.u!=b.u) return a.u<b.u;
    return a.v<b.v; 
}

int find(int a)
{
    if(fa[a]!=a) fa[a]=find(fa[a]);
    return fa[a];
}

int main(int argc, char *argv[]) 
{
    int n,m,i,j,k,t,u,v,w,fu,fv,amount,mstw,sec_mstw;  //amount记录生成树的边的条数 ,mstw表示最小生成树的权值之和,sec_mstw表示次小生成树的权值之和
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(i=0;i<m;i++)
        {
            scanf("%d %d %d",&u,&v,&w);
            array[i].u=u;
            array[i].v=v;
            array[i].w=w;       
        }
        
        sort(array,array+m,cmp);
        for(i=0;i<=n;i++) fa[i]=i;
        amount=mstw=0;
        
        for(i=0;i<=n;i++) head[i]=end[i]=i;
        memset(next,-1,sizeof(next));   
        memset(tag,false,sizeof(tag));
        sec_mstw=INF; 
        
        
        for(i=0;i<m;i++)
        {
            fu=find(array[i].u);
            fv=find(array[i].v); 
            if(fu==fv) continue;
            for(j=head[array[i].u];j!=-1;j=next[j])
            {
                for(k=head[array[i].v];k!=-1;k=next[k])
                {
                    length[j][k]=length[k][j]=array[i].w;
                }
            }
            
            next[end[array[i].u]]=head[array[i].v];
            end[array[i].u]=end[array[i].v];
            head[array[i].v]=head[array[i].u];
            
            fa[fu]=fv;
            tag[i]=true;
            mstw+=array[i].w;
            amount++;           
            if(amount==n-1) break;            
        }
        
        for(i=0;i<m;i++)
        {
            if(!tag[i])
            {
                sec_mstw=min(sec_mstw,mstw+array[i].w-length[array[i].u][array[i].v]);
                if(sec_mstw==mstw) break;
            }
        }
        if(sec_mstw!=mstw) printf("%d\n",mstw);
        else printf("Not Unique!\n");
    }
    system("PAUSE");
    return EXIT_SUCCESS;
}

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

The Unique MST
Time Limit: 1000MS Memory Limit: 10000K
   

Description

Given a connected undirected graph, tell if its minimum spanning tree is unique. 

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties: 
1. V' = V. 
2. T is connected and acyclic. 

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'. 

Input

The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.

Output

For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.

Sample Input

2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2

Sample Output

3
Not Unique!

      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值