您的位置:首页 > 其它

最小生成树和次小生成树

2014-03-31 22:51 288 查看
最小生成树和次小生成树定义:

生成树:图G的生成树包含原图中的全部顶点n,和n-1条边.

最小生成树就是所有生成树中边权和最小的.

2 那么如何求最小生成树呢?

介绍两种基于贪心的算法:

1.prim算法

设图G =(V,E),其生成树的顶点集合为U。

  ①、把v0放入U。

  ②、在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树。

  ③、把②找到的边的v加入U集合。如果U集合已有n个元素,则结束,否则继续执行②。

2.kruskal算法

首先将所有边按边权排序,然后按照边权从小到大依次处理.这里要用到并查集的思想,假设已有点集U,现在正在处理边i->j,如果i,j已在

U中则处理下一条边,否则将i,j加入并查集中.继续处理下一条边,直到有n-1条边为止.

3 次小生成树

次小生成树可由最小生成树换一条边得到

算法:

1)先用prim求出最小生成树T,在prim的同时,用一个矩阵max[u][v]记录在树中连接u-v的路径中权值最大的边.

2)枚举所有不在T中的边u-v,加入边u-v,删除权值为max[u][v]的边,不断枚举找到次小生成树.

次小生成树的模板:

#include<iostream>
using namespace std;
const int INF=0x3f3f3f3f;
int g[110][110],dist[110],mmax[110][110];
int pre[110];
bool mark[110];
bool connect[110][110];
int mst,mint;
int n,m;
int prim()
{
int res=0,fa,p,min,i,j;
memset(mmax,0,sizeof(mmax));
for(i=1;i<=n;i++)
{
dist[i]=g[1][i];
pre[i]=1;
mark[i]=false;
}
dist[1]=0;
mark[1]=true;
for(i=1;i<n;i++)
{
p=-1;min=INF;
for(j=1;j<=n;j++)
{
if(!mark[j]&&dist[j]<min)
{
p=j;
min=dist[j];
}
}
if(p==-1) return res;
mark[p]=true;
res+=dist[p];
fa=pre[p];
connect[fa][p]=false;
connect[p][fa]=false;
mmax[fa][p]=min;
for(j=1;j<=n;j++)
mmax[j][p]=(mmax[fa][p]>mmax[j][fa])?mmax[fa][p]:mmax[j][fa];
for(j=1;j<=n;j++)
{
if(!mark[j]&&dist[j]>g[p][j])
{
dist[j]=g[p][j];
pre[j]=p;
}
}
}
return res;
}

int main()
{
int tc;
//freopen("1.txt","r",stdin);
scanf("%d",&tc);
while(tc--)
{
scanf("%d %d",&n,&m);
memset(g,INF,sizeof(g));
memset(connect,false,sizeof(connect));
while(m--)
{
int u,v,c;
scanf("%d %d %d",&u,&v,&c);
g[u][v]=c;
g[v][u]=c;
connect[u][v]=true;
connect[v][u]=true;
}
mst=prim();
int i,j;
bool flag=false;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(connect[i][j]==false||g[i][j]==INF)
continue;
if(g[i][j]==mmax[i][j])
{
flag=true;
break;
}
}
if(flag)
printf("Not Unique!\n");
else
printf("%d\n",mst);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: