您的位置:首页 > 其它

最小生成树和次小生成树

2015-01-30 14:59 190 查看
转自:可笑痴狂 http://www.cnblogs.com/dongsheng/articles/2617186.html
最小生成树和次小生成树定义:

生成树:图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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: