关于次小生成树的构造:
在求最小生成树时,用数组Max[i][j]来表示MST中i到j最大边权。
求完后,直接枚举所有不在MST中的边,把它加入到MST中构成一棵新的树,且该树有环,此环是由刚加入的边(i,j)造成的,所以可以通过删除Max[i][j]即可得到新的一颗树,且所有的该类树中必有一棵为次小生成树。
如图所示:
G,H不是MST上的边,通过加入边(G,H),得到一个环(B,H,G),由于在计算最小生成树时已经计算出G,H之间最大边权为Max[G][H] = BH,所以通过删除BH即可得到一棵此时最小的生成树,然后更新答案即可。
实际上,我们知道MST的构造是具有贪心性质的,假如上图是一棵MST的话,那么必然有w(B,H) < w(G,H)。实际上w(B,H)是G->H的第二大边权,所以我们可以增加w(G,H),然后删除w(B,H)得到的是权值和第二大的树,这时我们就可以通过枚举所有不在MST树中(!use[i][j])的办法来生成次小生成树。
CODE:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int N, M;
int w[MAXN][MAXN] ,d[MAXN];
bool vis[MAXN], use[MAXN][MAXN];
int cnt ,fa[MAXN], Max[MAXN][MAXN] ;
void init()
{
cnt = 0;
memset(use, 0, sizeof(use));
memset(vis, 0, sizeof(vis));
memset(w, INF, sizeof(w));
memset(Max, 0, sizeof(Max));
}
void Prim(int src)
{
for(int i = 1; i <= N; i++) d[i] = (i == src)? 0:INF;
for(int i = 1; i <= N; i++) fa[i] = i;
for(int i = 1; i <= N; i++)
{
int m = INF, x ;
for(int y = 1; y <= N; y++) if(!vis[y] && d[y] < m) m = d[x=y];
for(int y = 1; y <= N; y++) if(vis[y])/*这是算法的关键,记录下vis[y]到k的路径中权值最大的值,用于替换处理*/
{
Max[x][y] = Max[y][x] = max(Max[y][fa[x]], d[x]); //这里我出现了一个非常严重的错误,POJ竟然没报错!!
//Max[x][y] = Max[y][x] = d[x];
}
vis[x] = 1;
use[x][fa[x]] = use[fa[x]][x] = 1; //标记在MST树中
cnt += m;
for(int y = 1; y <= N; y++)
{
if(!vis[y] && d[y] > w[x][y])
{
d[y] = w[x][y];
fa[y] = x; //记录父亲节点
}
}
}
}
int smst() //second MST
{
int Min = INF;
for(int i = 1; i <= N; i++)
{
for(int j = i+1; j <= N; j++)
{
if(w[i][j] != INF && !use[i][j])
{
int res = cnt + w[i][j] - Max[i][j];
Min = min(Min, res);
}
}
}
if(Min == cnt) return 0;
return 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d%d", &N, &M);
while(M--)
{
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
if(w[u][v] > cost) //可能有重边
{
w[u][v] = w[v][u] = cost;
}
}
Prim(1);
if(smst())
{
printf("%d\n", cnt);
}
else printf("Not Unique!\n");
}
return 0;
}
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int N, M;
int w[MAXN][MAXN] ,d[MAXN];
bool vis[MAXN], use[MAXN][MAXN];
int cnt ,fa[MAXN], Max[MAXN][MAXN] ;
void init()
{
cnt = 0;
memset(use, 0, sizeof(use));
memset(vis, 0, sizeof(vis));
memset(w, INF, sizeof(w));
memset(Max, 0, sizeof(Max));
}
void Prim(int src)
{
for(int i = 1; i <= N; i++) d[i] = (i == src)? 0:INF;
for(int i = 1; i <= N; i++) fa[i] = i;
for(int i = 1; i <= N; i++)
{
int m = INF, x ;
for(int y = 1; y <= N; y++) if(!vis[y] && d[y] < m) m = d[x=y];
for(int y = 1; y <= N; y++) if(vis[y])/*这是算法的关键,记录下vis[y]到k的路径中权值最大的值,用于替换处理*/
{
Max[x][y] = Max[y][x] = max(Max[y][fa[x]], d[x]); //这里我出现了一个非常严重的错误,POJ竟然没报错!!
//Max[x][y] = Max[y][x] = d[x];
}
vis[x] = 1;
use[x][fa[x]] = use[fa[x]][x] = 1; //标记在MST树中
cnt += m;
for(int y = 1; y <= N; y++)
{
if(!vis[y] && d[y] > w[x][y])
{
d[y] = w[x][y];
fa[y] = x; //记录父亲节点
}
}
}
}
int smst() //second MST
{
int Min = INF;
for(int i = 1; i <= N; i++)
{
for(int j = i+1; j <= N; j++)
{
if(w[i][j] != INF && !use[i][j])
{
int res = cnt + w[i][j] - Max[i][j];
Min = min(Min, res);
}
}
}
if(Min == cnt) return 0;
return 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d%d", &N, &M);
while(M--)
{
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
if(w[u][v] > cost) //可能有重边
{
w[u][v] = w[v][u] = cost;
}
}
Prim(1);
if(smst())
{
printf("%d\n", cnt);
}
else printf("Not Unique!\n");
}
return 0;
}
CODE:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int n, m;
int w[MAXN][MAXN], d[MAXN];
bool vis[MAXN], use[MAXN][MAXN];
int cnt ,fa[MAXN], path[MAXN][MAXN];
void init()
{
cnt = 0;
memset(use, 0, sizeof(use));
memset(vis, 0, sizeof(vis));
memset(w, INF, sizeof(w));
memset(path, 0, sizeof(path));
}
void Prim(int src)
{
for(int i = 1; i <= n; i++) { d[i] = (i == src)?0:INF; fa[i] = i; }
for(int i = 1; i <= n; i++)
{
int x, m = INF;
for(int y = 1; y <= n; y++) if(!vis[y] && m > d[y]) m = d[x=y];
for(int y = 1; y <= n; y++) if(vis[y]) //更新
{
path[x][y] = path[y][x] = max(path[y][fa[x]], d[x]);
}
vis[x] = 1;
use[x][fa[x]] = use[fa[x]][x] = 1;
cnt += m;
for(int y = 1; y <= n; y++) if(d[y] > w[x][y])
{
d[y] = w[x][y];
fa[y] = x;
}
}
}
int smst()
{
int Min = INF, res;
for(int i = 1; i <= n; i++)
{
for(int j = i+1; j <= n; j++) if(w[i][j] != INF && !use[i][j]) //枚举
{
res = cnt + w[i][j] - path[i][j];
Min = min(Min, res);
}
}
if(Min == cnt) return 0;
return 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d%d", &n, &m);
while(m--)
{
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
if(w[u][v] > cost) //可能有重边
{
w[u][v] = w[v][u] = cost;
}
}
Prim(1);
if(smst())
{
printf("%d\n", cnt);
}
else printf("Not Unique!\n");
}
return 0;
}
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int n, m;
int w[MAXN][MAXN], d[MAXN];
bool vis[MAXN], use[MAXN][MAXN];
int cnt ,fa[MAXN], path[MAXN][MAXN];
void init()
{
cnt = 0;
memset(use, 0, sizeof(use));
memset(vis, 0, sizeof(vis));
memset(w, INF, sizeof(w));
memset(path, 0, sizeof(path));
}
void Prim(int src)
{
for(int i = 1; i <= n; i++) { d[i] = (i == src)?0:INF; fa[i] = i; }
for(int i = 1; i <= n; i++)
{
int x, m = INF;
for(int y = 1; y <= n; y++) if(!vis[y] && m > d[y]) m = d[x=y];
for(int y = 1; y <= n; y++) if(vis[y]) //更新
{
path[x][y] = path[y][x] = max(path[y][fa[x]], d[x]);
}
vis[x] = 1;
use[x][fa[x]] = use[fa[x]][x] = 1;
cnt += m;
for(int y = 1; y <= n; y++) if(d[y] > w[x][y])
{
d[y] = w[x][y];
fa[y] = x;
}
}
}
int smst()
{
int Min = INF, res;
for(int i = 1; i <= n; i++)
{
for(int j = i+1; j <= n; j++) if(w[i][j] != INF && !use[i][j]) //枚举
{
res = cnt + w[i][j] - path[i][j];
Min = min(Min, res);
}
}
if(Min == cnt) return 0;
return 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d%d", &n, &m);
while(m--)
{
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
if(w[u][v] > cost) //可能有重边
{
w[u][v] = w[v][u] = cost;
}
}
Prim(1);
if(smst())
{
printf("%d\n", cnt);
}
else printf("Not Unique!\n");
}
return 0;
}