prim:
先用prim求出最小生成树T,在prim的同时,用一个矩阵maxd[u][v] 记录 在T中连结任意两点u,v的唯一的路中权值最大的那条边的权值,这是很容易做到的,因为prim是每次增加一个结点s, 在此需要保存节点和其父节点,采用DP,则最大权值要么是新加入的边,要么是父节点到起始点的采用DP算出来的距离。即:
maxd[j][p] = max[p][j] = lowc[p] > max[j][closest[p]] ? lowc[p] : max[j][closest[p]] ;
枚举所有不在T中的边uv, 加入边uv则必然替换权为maxd[u][v]的边,这样才能保证次小。
const int INF=0x3f3f3f3f;
const int MAXN=110;
bool vis[MAXN],used[MAXN][MAXN];
int lowc[MAXN],closest[MAXN],maxd[MAXN][MAXN];
int Prim(int cost[][MAXN],int n)//点是0~n-1
{
int ans=0;
memset(vis,false,sizeof(vis));
vis[0]=true;
lowc[0]=0;
for(int i=1; i
{
lowc[i]=cost[0][i];//初始点到各点的距离
closest[i]=1;
}
for(int i=1; i
{
int minc=INF;
int p=-1;
for(int j=0; j
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
if(minc==INF)return -1;//原图不连通
ans+=minc;
vis[p]=true;//p点已访问
used[p][closest[p]]=used[closest[p]][p]=true;
for(int j=0; j
{
///重点
if(vis[j]&&j!=p)
{
maxd[j][p] = maxd[p][j] = lowc[p] > maxd[j][closest[p]] ? lowc[p] : maxd[j][closest[p]] ;
}
if(!vis[j]&&lowc[j]>cost[p][j])
{
lowc[j]=cost[p][j];//p点到各点的距离
closest[j]=p;
}
}
}
return ans;
}
还有一步枚举,这里就不写了。
kruskal:
多次求最小树: 首先,用kruskal求得最小生成树,并用visit数组记录最小生成树的边,假设为总共num条 然后,循环求最小生成树num次,每次都不用第一次求得的最小生成树的边
假设:第一次求最小生成树用到了 1、2、4这三条边,总共5条边,那循环3次的时候,每次分别不用1、2、4求得最小生成树的MST,最小的MST即为次小生成树。
#include
#include
#include
#include
using namespace std;
#define M 99999999
int n, m,w;
int f[10005], sum, cou;
int visit[10005];
struct edge
{
int u;
int v;
int w;
};
edge e[10005];
void init()
{
int i;
for (i = 1; i <= n; i++)
{
f[i] = i;
}
}
int cmp(edge a, edge b)
{
return a.wint getf(int v)
{
if (f[v] == v)
return v;
else
{
f[v] = getf(f[v]);
return f[v];
}
}
int merg(int v, int u)
{
int t1, t2;
t1 = getf(v);
t2 = getf(u);
if (t1 != t2)
{
f[t2] = t1;
return 1;
}
return 0;
}
int mintree()
{
int i,flag;
init();
flag = 0;
w = 0;
cou = 0;
for (i = 1; i <= m; i++)
{
if (merg(e[i].v, e[i].u))
{
cou++;
visit[w++] = i;
}
if (cou == n - 1)
{
flag = 1;
break;
}
}
//cout << sum << endl;
return flag ;
}
///重点
int cimintree()
{
int j, flag,min;
min = M;
for (int i = 0; i < w; i++)
{
flag = 0;
init();
cou = 0;
sum = 0;
for (j = 1; j <= m; j++)
{
if (j != visit[i])
{
if (merg(e[j].v, e[j].u))
{
cou++;
sum = sum + e[j].w;
}
if (cou == n - 1)
{
flag = 1;
break;
}
}
}
if (flag&&sum < min) min = sum;
}
min = (min == M) ? -1 : min;
return min;
}
int main()
{
int i,flag,min;
while (scanf("%d %d", &n,&m) != EOF)
{
if (n == 0)
break;
sum = 0;
cou = 0;
memset(e, 0, sizeof(e));
memset(f, 0, sizeof(f));
for (i = 1; i <= m; i++)
{
scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
}
sort(e + 1, e + m + 1, cmp);
flag = mintree();
if (flag == 0)
{
cout << "-1" << endl;
}
else
{
min = cimintree();
cout << min << endl;
}
}
return 0;
}