次小生成树

来源:互联网 发布:施乐s1810网络设置 编辑:程序博客网 时间:2024/04/27 00:43

次小生成树

    最小生成树的算法想必大家都很了解,主要有kruskal和prim。但如果要求次小生成树(即第二小的生成树)呢?

    一种容易想到的方法是枚举删除最小生成树上的边,再求最小生成树。用kruskal这种算法的复杂度为O(n*elog2e),当图比较稠密时,复杂度接近O(n^3)。

    但有一种更简单的方法:先求最小生成树T,枚举添加不在T中的边,则添加后一定会形成环。找到环上边值第二大的边(即环中属于T中的最大边),把它删掉,计算当前生成树的权值,取所有枚举修改的生成树的最小值,即为次小生成树。

    这种方法在实现时有更简单的方法:首先求最小生成树T,然后从每个结点u遍历最小生成树T,用一个二维数组max[u][v]记录结点u到结点v的路劲上边的最大值(即最大边的值)。然后枚举不在T中的边(u,v),计算T- max[u][v] + w(u,v)的最小值,即为次小生成树的权值。显然,这种方法的时间复杂度为O(n^2 + e)。

    可见,第二种算法将原来的时间复杂度O(n^3)提高到了O(n^2)。

 

    例:判断生成树的唯一性,唯一则输出权值,不唯一输出Not Unique!(POJ1679)

显然,可以转化为求次小生成树,次小生成树权值=最小生成树,则不唯一。

#include <iostream>#include <algorithm>#include <queue>const int INF = 0x7fffffff;const int MAX = 10001;int n,m;int num;int p[MAX];int max[101][101];struct Edge//原始图{int from;int to;int w;bool flag;}e[MAX];struct Tree//最小生成树{int to;int w;int next;}tree[202];int index[101];struct Node//生成树的结点{int seq;//结点编号int max;//从某个点到它的路径中的最大边的长度};bool cmp(const Edge &a, const Edge &b){return a.w < b.w;}void makeSet(){for(int i = 0; i <= n; i++){p[i] = i;}}int findSet(int x){if(x != p[x])p[x] = findSet(p[x]);return p[x];}void addEdge(int from, int to, int w){tree[num].to = to;tree[num].w = w;tree[num].next = index[from];index[from] = num++;}int kruscal(){int i,j;int x, y;int edgeNum = 0;int result = 0;makeSet();std::sort(e,e+m,cmp);for(i = 0; i < m; i++){x = findSet(e[i].from);y = findSet(e[i].to);if(x != y){edgeNum++;addEdge(e[i].from,e[i].to,e[i].w);addEdge(e[i].to,e[i].from,e[i].w);e[i].flag = true;p[x] = y;result += e[i].w;}}return edgeNum == n-1 ? result : -1;}void bfs(int p){int i,j;bool used[101];memset(used,0,sizeof(used));std::queue<Node> que;Node now,adj;now.max = 0;now.seq = p;que.push(now);used[p] = true;while(!que.empty()){Node q = que.front();que.pop();for(i = index[q.seq]; i != -1; i = tree[i].next){adj.seq = tree[i].to;adj.max = tree[i].w;if(!used[adj.seq]){if(q.max > adj.max)adj.max = q.max;max[p][adj.seq] = adj.max;used[adj.seq] = true;que.push(adj);}}}}void second_MST(){int i,j;int mst = kruscal();for(i = 1; i <= n; i++)bfs(i);int smst = INF;for(i = 0; i < m; i++){if(!e[i].flag){if(mst + e[i].w - max[e[i].from][e[i].to] < smst)smst = mst + e[i].w - max[e[i].from][e[i].to];}}if(smst == mst)printf("Not Unique!\n");elseprintf("%d\n",mst);}int main(){int i,j;int cases;int a,b,w;scanf("%d",&cases);while(cases--){scanf("%d %d",&n,&m);for(i = 0; i < m; i++){scanf("%d %d %d",&e[i].from,&e[i].to,&e[i].w);e[i].flag = false;}num = 0;memset(index,-1,sizeof(index));second_MST();}return 0;}


0 0
原创粉丝点击