【次小生成树】:
最小生成树是求一个图中的一棵树,满足树上的边的权值和最小。
次小生成树的话,顾名思义,就是权值和仅次于最小生成树的树。
一般,次小生成树的求法只需在最小生成树的算法上改进一下。
本文以最小生成树的kruscal(克鲁斯卡尔)算法(并查集为辅)讲解。
【关键字】
最大瓶颈边:指从点u到v的所有可到达路径中,经过的最大边(仅仅这一个边,不是整个路径)。
链式前向星:最小生成树建图用邻接表,邻接表通过链式前向星实现。
【解题思路】
最小生成树的算法就不啰嗦了、这里以kruscal算法讲解。
当我们求出最小生成树之后,想求次小的,其实就是删掉其中的某个边,然后加入一条新边。
即边的交换。(如果交换的这两条边相等,那么最小生成树==次小生成树)
假设要添加上的边是,那么在树中从u到v的路径中就得断开(保证是一棵树)
要断开,可以删边,且只能删一条。
删哪一条呢?
删权值最大的那条。因为我们要保证换边后,树的权值和要增加的最少。
【解题步骤】
1、首先计算图的最小生成树,并且在加边过程中,把最小生成树建图,同时把没添加的边存在数组q[]里。复杂度O(m)
2、数组q[]的首元素代表的边,就是可以作为替换的边。
3、设要添的这个边是,则需要减掉树上u->v路径上的最大边,dfs找到这个最大边即可。复杂度O(n)
4、至此,次小生成树就求出来了。
此算法不能求第k小生成树,只能求次小。第k小的话可能要结合dp,我没试过。。
整个算法的复杂度为O(m+n)
【例题poj1679】
题目地址:http://poj.org/problem?id=1679
The Unique MST
Time Limit: 1000MS |
|
Memory Limit: 10000K |
Total Submissions: 32145 |
|
Accepted: 11631 |
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!
【题意】:
给出一个无向图,问其最小生成树是否唯一?也就是最小生成树,是否存在相等的次小生成树
【分析】:
用上文讲解思路的求出要添的那个边,和要删的那个边,看是否相等即可
【代码】:
- #include
- #include
- #include
- #include
- using namespace std;
- struct node{
- int s,t,len;
- int next;
- }e[20101];
- int head[1010];
- int pre[1015];
- int q[20100],top;
- int T,n,m,u,v,len;
- int find(int x)
- {
- if(pre[x]==x)return x;
- return pre[x]=find(pre[x]);
- }
- void join(int x,int y)
- {
- int fx=find(x),fy=find(y);
- if(fx!=fy)pre[fx]=fy;
- }
- bool cmp(node a,node b)
- {
- return a.len
- }
- int kruscal()
- {
- int ans=0;
- sort(e+1,e+m+1,cmp);
- memset(head,-1,sizeof(head));
- top=0;
- for(int i=1;i<=m;i++)
- {
- int &u=e[i].s,&v=e[i].t;
- if(find(u)!=find(v))
- {
- ans+=e[i].len;
- join(u,v);
- e[i].next=head[u];
- head[u]=i;
- e[i+m]=node{v,u,e[i].len,head[v]};
- head[v]=i+m;
- }
- else
- q[top++]=i;
-
- }
- return ans;
- }
- int dfs(int s,int t,int last=-1,int maxside=0)
- {
- if(s==t)return maxside;
- int temp=0x3f3f3f3f;
- for(int i=head[s];~i;i=e[i].next)
- {
- if(e[i].t!=last)
- temp=min(temp,dfs(e[i].t,t,e[i].s,max(maxside,e[i].len)));
- }
- return temp;
- }
- int main()
- {
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d%d",&n,&m);
- for(int i=1;i<=n;i++)pre[i]=i;
- for(int i=1;i<=m;i++)
- {
- scanf("%d%d%d",&u,&v,&len);
- e[i]=node{u,v,len};
- }
- int ans=kruscal();
- if(top&&e[q[0]].len==dfs(e[q[0]].s,e[q[0]].t))
- puts("Not Unique!");
- else printf("%d\n",ans);
- }
- return 0;
- }