题意:求连通图的最小和次小长度,三种情况:1.不存在最小 2.不存在次小 3.最小和次小不同。
无法使用prim求次小生成树,因为可能有两个点有两个及以上权值(有重边),那么我们用prim会把大的权值覆盖掉,所以我们用kruskal求,我们求出最小生成树后,把用过的边绕过,求最小生成树,如果存在则存在
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
int n,m;
struct node
{
int x,y,v;
}e[210];
int cmp(node a,node b)
{
return a.v < b.v;
}
int f[201],r[210];
void init()
{
for(int i=0;i<=n;i++)
f[i] = i;
}
int getf(int v)
{
if(v == f[v])
return v;
else
{
f[v] = getf(f[v]);
return f[v];
}
}
int main()
{
int T,i,j;
scanf("%d",&T);
int t = 1;
while(T--)
{
scanf("%d %d",&n,&m);
for(i=0;i<m;i++)
scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].v);
printf("Case #%d : ",t++);
init();
int sum = 0;
int k = 0;
sort(e,e+m,cmp);//将所有边排序,按从小到大加入并查集,且不形成环
for(i=0;i<m;i++)
{
int dx = getf(e[i].x);
int dy = getf(e[i].y);
if(dx != dy)
{
f[dx] = dy;
sum += e[i].v;
r[k++] = i;
}
if(k == n-1)
break;
}
if(k!=n-1)//无法形成最小生成树
{
printf("No way\n");
continue;
}
int Min = INF;
for(i=0;i<k;i++)
{
init();
int kk = 0;
int summ = 0;
for(j=0;j<m;j++)//加入没有访问过的边,看能否形成生成树(枚举每一个没遍历的边)
{
if(j == r[i])
continue;
int dx = getf(e[j].x);
int dy = getf(e[j].y);
if(dy!=dx)
{
f[dx] = dy;
summ += e[j].v;
kk++;
}
if(kk == n-1) break;
}
if(kk == n-1)//所有的生成树里面最小的那个就是次小生成树
Min = min(summ,Min);
}
if(Min == INF)
printf("No second way\n");
else
printf("%d\n",Min);
}
return 0;
}