题目链接:https://cn.vjudge.net/contest/67265#problem/C
具体思路:和判断最小生成树是否唯一的思路差不多,首先跑一遍最小生成树,在求最小生成树的过程中记录任意两个点之间的最大权值,然后试着暴力,如果有一条边没有在最小生成树上,那么就先加上这条边的权值,再去减去两个端点之间的最大权值,求一个最小值,这就是次小生成树。
AC代码:
#include<iostream>
#include<string>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
# define ll long long
# define inf 0x3f3f3f3f
# define maxn 1000+100
# define eps 1e-6
int a[maxn][maxn];
int used[maxn][maxn];
int vis[maxn];
int maxx[maxn][maxn];
int father[maxn];
int dis[maxn];
int n,m;
int mst;
void init()
{
memset(vis,0,sizeof(vis));
memset(used,0,sizeof(used));
memset(dis,inf,sizeof(dis));
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i==j)
a[i][j]=0;
else a[i][j]=inf;
maxx[i][j]=0;
}
}
}
void prim()
{
vis[1]=1;
dis[1]=0;
for(int i=1; i<=n; i++)
{
father[i]=1;
dis[i]=a[1][i];
}
father[1]=-1;
for(int i=1; i<n; i++)
{
int minn=inf,index=-1;
for(int j=1; j<=n; j++)
{
if(vis[j]==0&&dis[j]<minn)
{
minn=dis[j];
index=j;
}
}
if(index==-1)return ;
vis[index]=1;
mst+=minn;
if(father[index]!=-1)
used[father[index]][index]=used[index][father[index]]=1;
for(int j=1; j<=n; j++)
{
if(vis[j]==0&&dis[j]>a[index][j])
{
dis[j]=a[index][j];
father[j]=index;
}
else if(vis[j]&&j!=index)
{
maxx[index][j]=maxx[j][index]=max(maxx[father[index]][j],dis[index]);
}
}
}
}
int judge()
{
int ans=inf;
for(int i=1; i<=n; i++)
{
for(int j=1+i; j<=n; j++)
{
if(i==j)continue;
if(!used[i][j]&&a[i][j]!=inf)
{
// cout<<i<<" "<<j<<" "<<a[i][j]<<" "<<maxx[i][j]<<endl;
ans=min(ans,mst+a[i][j]-maxx[i][j]);
}
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
int t1,t2,t3;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
if(t3<a[t1][t2])
{
a[t2][t1]=a[t1][t2]=t3;
}
}
mst=0;
prim();
printf("%d",mst);
printf(" %d
",judge());
}
return 0;
}