给出图,要求是否有生成树,是否有次小生成树,输出次小生成树花费
因为给出的图有重边,所以不能用prim求次小,改用kruskal
先用kruskal求出最小生成树,并记录所用边
接下来枚举删去所用边,再生成一次最小生成树,其中最小的就是次小生成树
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=100+10;
const int M=200+10;
const int INF=0x7f7f7f7f;
struct Edge
{
int u,v,w;
bool operator < (const Edge &a) const
{
return w<a.w;
}
}edge[M];
int tot;
void addedge(int u,int v,int w)
{
edge[tot].u=u;
edge[tot].v=v;
edge[tot++].w=w;
}
int uf[N];
int find(int u)
{
if(uf[u]==-1) return u;
return uf[u]=find(uf[u]);
}
int used[N];
void solve(int n,int kase)
{
printf("Case #%d : ",kase);
int ans1=0;
bool flag=false;
sort(edge,edge+tot);
memset(uf,-1,sizeof(uf));
int cnt=0;
for(int i=0;i<tot;i++)
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int ru=find(u);
int rv=find(v);
if(ru!=rv)
{
ans1+=w;
used[cnt]=i;
cnt++;
uf[ru]=rv;
if(cnt==n-1)
{
flag=true;
break;
}
}
}
if(!flag&&n>1)
{
printf("No way\n");
return;
}
int ans2=INF;
for(int k=0;k<n-1;k++)
{
cnt=0;
int t=0;
flag=false;
memset(uf,-1,sizeof(uf));
for(int i=0;i<tot;i++)
{
if(i==used[k]) continue;
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int ru=find(u);
int rv=find(v);
if(ru!=rv)
{
t+=w;
cnt++;
uf[ru]=rv;
if(cnt==n-1)
{
flag=true;
break;
}
}
}
if(flag) ans2=min(ans2,t);
}
if(ans2==INF) printf("No second way\n");
else printf("%d\n",ans2);
}
int main()
{
int T,kase=0;
int n,m;
int a,b,c;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
tot=0;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
}
solve(n,++kase);
}
return 0;
}