次小生成树

来源:互联网 发布:没有c基础可以学java吗 编辑:程序博客网 时间:2024/05/17 21:11

次小生成树的思想就是在最小生成树的基础上,去掉最小生成树中的一条边,在加入不在最先生成树中的一条边,并对重新生成的生成树选取权值最小的生成树,即为次小生成树。

次小生成树的主要思路就是在prim算法求最小生成树的过程中,标记mmax[u][v]区间中的最大权值的边,可以这么理解


假设此时u到v的边已经在最小生成树中,mmax[u][v]存储的就是在这些从u到v 的边中权值最大的边,即为边u到m 的权值,这样在求次小生成树的时候如果存在另外的map[u][v]的边就可以直接将边u到m的边去除,并加入map[u][m]边得到此下生成树。在得到最小生成树之后,需要对没有加入的所有边进行检索并建立新的生成树。

如果还是不懂可以看一看这个博客,很好的,http://www.cnblogs.com/hxsyl/p/3290832.html

次小生成树的模板如下:(实际上是poj1679的代码)

#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;} 


代码如下

#include<iostream>#include <cstdio>#include <cstring>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);       int second_strr[110];       while(tc--)       {              scanf("%d %d",&n,&m);              memset(g,INF,sizeof(g));              memset(connect,false,sizeof(connect));              memset(second_strr,0,sizeof(second_strr));              //int k =0;              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;              int min_mst = INF;              //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(min_mst>mst+g[i][j]-mmax[i][j])          //求次小生成树                                  min_mst = mst+g[i][j]-mmax[i][j];                     }                     printf("mst>>>>%d\n",mst);                     printf("min_mst>>%d\n",min_mst);       }       return 0;}/*16 81 2 32 3 41 3 51 4 63 4 53 5 64 5 75 6 7*/


0 0
原创粉丝点击