次小生成树:把所有生成树按照权值之和从小到大的顺序排列,求排在第二位的生成树。
次小生成树可能也是最小生成树;
次小生成树可以通过有最小生成树换一条边得到;
次小生成树的求法:时间复杂度为:V^2(V为节点数)
(1)、用prim算法求出最小生成树T,在prim的同时,用一个矩阵max_val[u][v]记录在T中连接任意两点u,v的唯一路中权值最大的那条边的权值;
求max_val[u][v]:
在prim算法中,设已经被标记的节点集合为W,每次增加一个接点s的时候,容易求出所有节点到s的路中的最大边权值:
设u属于W,且s是被连到W中的v点,则有:
max_val[v][s] = 边(v,s)的值;
max_val[u][s] = max(max_val[u][v],max_val[v][s]);
(2)、枚举所有不在T中的边(u,v),加入边(u,v)则必然替换权值为max_val[u][v]的边,枚举一次就得到一颗新的生成树,如果在这些生成树中,有权值和原最小生树相等的,则最小生成树不唯一,其中权值最小的一颗生成树就是次小生成树;
其中max_val[][] 的求法是维护信息代替重新计算,能够减少不必要的计算,降低时间复杂度,是很好的解题思想;
poj 2831次小生成树模板;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<map>
#define ll long long
#define MAX 101000
#define MAXN 1010
#define INF 2000000000
#define eps 1e-8
using namespace std;
struct Edge{
int from,to,dist;
}E[MAX];
struct Node{
int u,w,pre;
bool operator < (const Node& rhs) const{
return rhs.w < w;
}
};
vector<int>G[MAXN];
vector<Edge>edges;
int n;
void init(){
for (int i=0; i<=n; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int dist){
edges.push_back((Edge){from,to,dist});
int k = edges.size();
G[from].push_back(k-1);
}
int max_val[MAXN][MAXN];
void prim(int s){
int d[MAXN],vis[MAXN],p[MAXN],val[MAXN]; //p[]记录生成树中与该节点相连的节点,val[]记录已经被标记的节点
priority_queue<Node>q;
int cnt = 0;
memset(max_val,0,sizeof(max_val));
memset(vis,0,sizeof(vis));
memset(p,-1,sizeof(p));
for (int i=0; i<=n; i++) d[i] = (i == s ? 0 : INF);
q.push((Node){s,0,-1});
while (!q.empty()){
Node t = q.top();
q.pop();
if (vis[t.u]) continue;
int v = t.u;
vis[v] = 1;
if (v != s){ //当加入的节点不是根节点时,更新相应max_val[][]
max_val[t.pre][v] = max_val[v][t.pre] = t.w;
for (int i=0; i<cnt; i++) max_val[val[i]][v] = max_val[v][val[i]] = max(max_val[val[i]][t.pre], t.w);
}
val[cnt++] = v;
for (int i=0; i<G[v].size(); i++){
Edge e = edges[G[v][i]];
if (!vis[e.to]){
if (d[e.to] > e.dist){
d[e.to] = e.dist;
p[e.to] = v;
}
q.push((Node){e.to,d[e.to],p[e.to]});
}
}
}
}
int main(){
int m,Q;
while (scanf("%d%d%d",&n,&m,&Q) != EOF){
int a,b,c;
init();
for (int i=0; i<m; i++){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
addEdge(b,a,c);
E[i] = (Edge){a,b,c};
}
prim(1);
for (int i=0; i<Q; i++){
scanf("%d%d",&a,&b);
int u = E[a-1].from;
int v = E[a-1].to;
if (b <= max_val[u][v]){
printf("Yes\n");
}
else{
printf("No\n");
}
}
}
return 0;
}
poj1679 次小生成树模板;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<map>
#define ll long long
#define MAX 20000
#define MAXN 110
#define INF 2000000000
#define eps 1e-8
using namespace std;
struct Edge{
int from,to,dist;
};
struct Node{ //注意优先队列要维护的节点信息,和最小生成树的不同之处
int u,w,pre,edg;
bool operator < (const Node& rhs) const{
return rhs.w < w;
}
};
vector<int>G[MAXN];
vector<Edge>edges;
int n;
void init(){
for (int i=0; i<=n; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int dist){
edges.push_back((Edge){from,to,dist});
int k = edges.size();
G[from].push_back(k-1);
}
int max_val[MAXN][MAXN],ep[MAXN]; //ep[]记录最小生成树中与节点相连的边的编号,即记录最小生成树中的边(次小生成树要中未被标记的边枚举)
int prim(int s){
int d[MAXN],vis[MAXN],p[MAXN],val[MAXN]; //数组作用同上
priority_queue<Node>q;
int cnt = 0,ans = 0;
memset(max_val,0,sizeof(max_val));
memset(vis,0,sizeof(vis));
memset(p,-1,sizeof(p));
memset(ep,-1,sizeof(ep));
for (int i=0; i<=n; i++) d[i] = (i == s ? 0 : INF);
q.push((Node){s,0,-1,-1});
while (!q.empty()){
Node t = q.top();
q.pop();
if (vis[t.u]) continue;
ans += t.w;
int v = t.u;
vis[v] = 1;
if (v != s){
max_val[t.pre][v] = max_val[v][t.pre] = t.w;
for (int i=0; i<cnt; i++) max_val[val[i]][v] = max_val[v][val[i]] = max(max_val[val[i]][t.pre], t.w);
}
val[cnt++] = v;
for (int i=0; i<G[v].size(); i++){
Edge e = edges[G[v][i]];
if (!vis[e.to]){
if (d[e.to] > e.dist){
d[e.to] = e.dist;
p[e.to] = v;
ep[e.to] = G[v][i];
}
q.push((Node){e.to,d[e.to],p[e.to],ep[e.to]});
}
}
}
return ans;
}
int mark[MAX];
bool check(){
memset(mark,0,sizeof(mark));
for (int i=1; i<=n; i++){
if (ep[i] != -1){
mark[ep[i]] = 1;
mark[ep[i]^1] = 1;
}
}
for (int i=0; i < edges.size(); i++){
if (!mark[i]){
Edge e = edges[i];
if (e.dist == max_val[e.from][e.to]) return true;
}
}
return false;
}
int main(){
int m,T;
scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&m);
int a,b,c;
init();
for (int i=0; i<m; i++){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
addEdge(b,a,c);
}
int ans = prim(1);
if (!check()){
printf("%d\n",ans);
}
else printf("Not Unique!\n");
}
return 0;
}