UVa 10600 ACM Contest and Blackout Posted on 2016-09-05 | In ACM | | Visitors 题目链接UVa 10600 方法:次小生成树 题目分析题目大意给出n个顶点m条边的无向图,问图中的最小生成树的权重和次小生成树的权重 解析直接上板子就行 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144#include <set>#include <map>#include <stack>#include <cmath>#include <queue>#include <cstdio>#include <string>#include <vector>#include <iomanip>#include <bitset>#include <cstring>#include <iostream>#include <iosfwd>#include <deque>#include <algorithm>#define Memset(a,val) memset(a,val,sizeof(a))#define PI acos(-1.0)#define PB push_back#define MP make_pair#define rt(n) (i == n ? '\n' : ' ')#define hi printf("Hi----------\n")#define debug(x) cout<<"Debug : ---"<<x<<"---"<<endl;#define debug2(x,y) cout<<"Debug : ---"<<x<<" , "<<y<<"---"<<endl;#define debug3(x,y,z) cout<<"Debug : ---"<<x<<" , "<<y<<" , "<<z<<"---"<<endl;#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;typedef pair<int,int> PII;typedef long long ll;const int maxn=100000+5;const int mod=1000000007;const int INF=0x3f3f3f3f;const double eps=1e-8;// 顶点下标1~nconst int Vmax = 105;namespace SMST{ // MST int n;//n个顶点 int s;//起点 树的根 int weight; //MST的重量 int mp[Vmax][Vmax]; int dis[Vmax]; //dis[i]表示指向i点的最短的边 bool vis[Vmax]; //标记该点是否在树上 int pre[Vmax];//记录前驱 //SMST int subweight; //SMST的重量 bool used[Vmax][Vmax]; //表示当前边有没有被用过 int maxd[Vmax][Vmax]; //maxd[u][v]表示 u-v路径上最大的边权 void init(int Vsz,int source=1){//默认起点为1 memset(mp, INF, sizeof(mp)); memset(dis, INF, sizeof(dis)); memset(used, 0, sizeof(used)); memset(maxd, 0, sizeof(maxd)); memset(vis, false, sizeof(vis)); n=Vsz; for (int i=0; i<=n; i++) { mp[i][i] = 0; } weight=0; dis[source] = 0; pre[source] = source; } //1~n的邻接矩阵 void adde(int u,int v,int w){ mp[u][v]=w; mp[v][u]=w; } int prim(){ /* 返回值说明: -1: 无生成树 weight: 最小生成树的重量 */ for(int i=1;i<=n;i++){ int pos=0; int minc = INF; for(int j=1;j<=n;j++){ if(!vis[j]&&dis[j]<minc){ pos=j; minc = dis[j]; } } if(minc == INF) return -1; //n个点不联通 无生成树 weight+=dis[pos]; used[pos][pre[pos]] = true; // for SMST used[pre[pos]][pos] = true; // for SMST vis[pos]=true; for(int j=1;j<=n;j++){ if (j == pos) continue; if(vis[j]) { maxd[j][pos] = maxd[pos][j] = max(dis[pos], maxd[j][pre[pos]]); } else if(!vis[j]&&mp[pos][j]<dis[j]){ dis[j]=mp[pos][j]; pre[j]=pos; } } } return weight; } int smst(){ /* 返回值说明: -1: 无生成树 -2: 有最小生成树 无次小生成树 (比如给出的图即为一棵树) subweight: 次小生成树的重量 */ if(prim() == -1) return -1; //无生成树 subweight = INF; for(int i = 1; i<= n; i++){ for(int j = i + 1; j <= n; j++){ if(mp[i][j]!=INF && !used[i][j]){ subweight = min(subweight, weight+mp[i][j]-maxd[i][j]); } } } if(subweight == INF) return -2; //只有唯一生成树 也就是说只有最小生成树 没有次小生成树 return subweight; }}using namespace SMST;int main(){ int T,n,m,u,v,w; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); init(n); for (int i=1; i<=m; i++) { scanf("%d%d%d",&u,&v,&w); adde(u, v, w); } smst(); printf("%d %d\n",weight,subweight); }}