UVA 10600 - ACM Contest and Blackout(次小生成树)
题目链接 https://cn.vjudge.net/problem/UVA-10600
【题意】
给定n个点m条边的无向带权图,输出最小生成树和次小生成树的权值(n<=100)
【思路】
求出最小生成树,然后预处理最小瓶颈路,枚举不在最小生成树中的边即可
#include<bits/stdc++.h>
using namespace std;
const int inf=2e9;
const int maxn=105;
const int maxm=5005;
struct Edge{
int from,to,dist;
Edge(int f,int t,int d):from(f),to(t),dist(d){}
bool operator<(const Edge& e)const{
return dist<e.dist;
}
};
int n,m;
int par[maxn],vis[maxm],used[maxn],f[maxn][maxn];
vector<Edge> edges,g[maxn];
int find(int x){ return par[x]==x?x:par[x]=find(par[x]); }
int kruscal(){
for(int i=0;i<=n;++i){ g[i].clear();par[i]=i; }
sort(edges.begin(),edges.end());
int ans=0,cnt=0;
for(int i=0;i<m;++i){
Edge& e=edges[i];
int x=find(e.from);
int y=find(e.to);
if(x!=y){
par[x]=y;
ans+=e.dist;
vis[i]=true;
g[e.from].push_back(Edge(e.from,e.to,e.dist));
g[e.to].push_back(Edge(e.to,e.from,e.dist));
if(++cnt==n-1) break;
}
}
return ans;
}
void dfs(int u){
used[u]=true;
for(int i=0;i<g[u].size();++i){
Edge& e=g[u][i];
int v=e.to;
if(!used[v]){
for(int x=1;x<=n;++x){
if(used[x])
f[x][v]=f[v][x]=max(f[u][x],e.dist);
}
dfs(v);
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
edges.clear();
for(int i=0;i<m;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edges.push_back(Edge(u,v,w));
}
memset(vis,0,sizeof(vis));
int mst=kruscal();
memset(used,0,sizeof(used));
memset(f,0,sizeof(f));
dfs(1);
int ans=inf;
for(int i=0;i<m;++i){
if(!vis[i]){
Edge& e=edges[i];
ans=min(ans,mst+e.dist-f[e.from][e.to]);
}
}
printf("%d %d\n",mst,ans);
}
return 0;
}