nyoj118 修路方案(求次小生成树)

来源:互联网 发布:jquery 遍历数组对象 编辑:程序博客网 时间:2024/05/01 23:52


修路方案

时间限制:3000 ms  |  内存限制:65535 KB
难度:5
描述

南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。

现在已经知道哪些城市之间可以修路,如果修路,花费是多少。

现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。

但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧。

输入
第一行输入一个整数T(1<T<20),表示测试数据的组数
每组测试数据的第一行是两个整数V,E,(3<V<500,10<E<200000)分别表示城市的个数和城市之间路的条数。数据保证所有的城市都有路相连。
随后的E行,每行有三个数字A B L,表示A号城市与B号城市之间修路花费为L。
输出
对于每组测试数据输出Yes或No(如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)
样例输入
23 31 2 12 3 23 1 34 41 2 22 3 23 4 24 1 2
样例输出
NoYes
来源
POJ题目改编
上传者
张云聪

对于最小生成树(可以用kruskal和prime算法求得,在这里我是用kruskal求得,如果不会请自己百度。),边的权值的和最小称为最小生成树。

而次小生成树就是除了最小生成树外的最小生成树。而且所有的次小生成树都是通过最小生成树的换边得到的。

所以难点就是如何换边。

对于如何换边:

1.先求出最小生成树,值为x。

2.一一枚举添加不在生成树上的边(这时候一定形成了一个环)

3.寻找环上的(最小生成树上的边)权值最大值与你所添加不在生成树上的边的权值比较,所得到的差值为min。

由于是一一枚举添加边,min有多个,求出最小的哪一个,所以次小生成树就为x+min。

所以对于这道题也就很简单了,只要min=0就代表有多种方案了。具体请看代码:

#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;struct node{int a,b,c,vis;}c[200005];int fa[505],v,e,stamp[505][505],visit[505];bool cmp(node a,node b){return a.c<b.c;}int find(int x){if(fa[x]!=x) fa[x]=find(fa[x]);return fa[x];}void init(){for(int i=1;i<=v;i++)fa[i]=i;}void comb(int x1,int x2,int cost)//存贮最小生成树的边{stamp[x1][x2]=stamp[x2][x1]=cost;}int sec_find(int x,int y,int min)//换边{if(x==y)return min;for(int i=1;i<=v;i++){if(stamp[x][i]&&!visit[i]){visit[x]=1;if(stamp[x][i]>min)min=stamp[x][i];sec_find(i,y,min);}}return min;}int main(){int ncase,mintree,sec;scanf("%d",&ncase);while(ncase--){memset(stamp,0,sizeof(stamp));memset(visit,0,sizeof(visit));scanf("%d %d",&v,&e);init();for(int i=0;i<e;i++)scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].c);sort(c,c+e,cmp);int mintree=0;for(int i=0;i<e;i++)//求最小生成树{int x1=find(c[i].a);int x2=find(c[i].b);if(x1!=x2)fa[x1]=x2,mintree+=c[i].c,c[i].vis=1,comb(x1,x2,c[i].c);elsec[i].vis=0;//对于不在最小生成树里面的边标记一下}int flag=0;for(int i=0;i<e;i++)if(!c[i].vis)//最小生成树之外的边{sec=sec_find(c[i].a,c[i].b,-1000000);if(sec==c[i].c){flag=1;break;}}if(flag)printf("Yes\n");elseprintf("No\n");}return 0;}


1 0