题目大意:给一张无向图,找出最小生成树和次小生成树。
题目分析:模板题。。。方法就是枚举所有的比最小生成树中两端点之间的最长边还要长的边,用它替换,再取一个最小的值便是次小生成树了。
代码如下:
# include<iostream> # include<cstdio> # include<cstring> # include<cstring> using namespace std; # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)) # define CLL(a,b,n) fill(a,a+n,b) const int N=105; const int INF=1<<30; int n,m,dis[N],dp[N][N],G[N][N],G1[N][N],vis[N]; int prim() { REP(i,0,n) REP(j,i,n) G1[i][j]=G1[j][i]=INF; CLL(dis,INF,n); CL(vis,0); REP(i,0,n) dis[i]=G[0][i]; dis[0]=0; vis[0]=1; int res=0; REP(k,1,n){ int minn=INF,u; REP(i,0,n) if(!vis[i]&&minn>dis[i]){ minn=dis[i]; u=i; } res+=dis[u]; vis[u]=1; REP(i,0,n) if(vis[i]&&G[i][u]==dis[u]){ G1[i][u]=G1[u][i]=dis[u]; break; } REP(i,0,n) if(!vis[i]&&dis[i]>G[u][i]) dis[i]=G[u][i]; } return res; } void dfs(int rt,int u,int w) { if(dp[rt][u]!=-1) return ; dp[rt][u]=w; REP(i,0,n) if(G1[u][i]!=INF) dfs(rt,i,max(w,G1[u][i])); } int main() { int T,a,b,c; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); REP(i,0,n) REP(j,i,n) G[i][j]=G[j][i]=INF; while(m--) { scanf("%d%d%d",&a,&b,&c); --a,--b; G[a][b]=G[b][a]=c; } int MST=prim(); CL(dp,-1); REP(i,0,n) dfs(i,i,0); int MST1=INF; REP(i,0,n) REP(j,i+1,n){ if(G[i][j]==INF||G1[i][j]<INF||G[i][j]<dp[i][j]) continue; MST1=min(MST1,MST-dp[i][j]+G[i][j]); } printf("%d %d ",MST,MST1); } return 0; }