无向图最小生成树、次小生成树,最短路模板

来源:互联网 发布:套利交易软件 编辑:程序博客网 时间:2024/05/13 04:50


最小生成树有两种模板,都比较简单。

prime算法:

#include<stdio.h>#include<string.h>#define MAX 99999999int g[110][110];int n;int prim(){    int low[110];    int flag[110];    memset(flag,0,sizeof(flag));    for(int i=1; i<=n; i++)    {        low[i]=g[1][i];    }    int count=0;    flag[1]=1;    for(int i=1; i<n; i++)    {        int min=MAX+1;        int k;        for(int j=1; j<=n; j++)        {            if(flag[j]==0&&min>low[j])            {                min=low[j];                k=j;            }        }        flag[k]=1;        count+=low[k];        for(int j=1; j<=n; j++)        {            if(flag[j]==0&&low[j]>g[j][k])            {                low[j]=g[j][k];            }        }    }    return count;}int main(){    while(scanf("%d",&n)!=EOF)    {               int sum;        sum=prim();        printf("%d\n",sum);    }    return 0;}



kruskal算法:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#define MAX 6005using namespace std;typedef struct{    int v1,v2,distance;} Edge;Edge roads[MAX+1];int  tree[110];bool cmp(const Edge&a,const Edge&b){    return a.distance<b.distance;}int Find(int x){    while(x!=tree[x])        x=tree[x];    int u=x,v;    while(tree[u]!=x)    {        v=tree[u];        tree[u]=x;        u=v;    }    return x;}void Union(int x,int y){    int fx=Find(x),fy=Find(y);    if(fx!=fy)        tree[fx]=fy;}int main(){    int n,q,a,b,i,j,k,tmp,sum;    while((scanf("%d",&n))!=EOF)    {               for(i=0; i<110; ++i)        {            tree[i]=i;        }        sort(roads,roads+k,cmp);        for(i=0,sum=0; i<k; ++i)        {            if(Find(roads[i].v1)!=Find(roads[i].v2))            {                Union(roads[i].v1,roads[i].v2);                sum+=roads[i].distance;            }        }        printf("%d\n",sum);    }    return 0;}



以下是次小生成树思想:

 邻集的概念:由T进行一次可行交换得到的新的生成树所组成的集合,称为树T的邻集,记为N(T);
 设T是图G的最小生成树,如果T1满足ω(T1)=min{ω(T’)|T’∈N(T)},则T1是G的次小生成树;
 首先先求该图的最小生成树T,时间复杂度O(Vlog2V+E);
 然后,求T的邻集中权值和最小的生成树,即图G 的次小生成树;
 如果只是简单的枚举,复杂度很高;
 首先枚举两条边的复杂度是O(VE),再判断该交换是否可行的复杂度是O(V),则总的时间复杂度是O(V2E);
 分析可知,每加入一条不在树上的边,总能形成一个环,只有删去环上的一条边,才能保证交换后仍然是生成树;
 而删去边的权值越大,新得到的生成树的权值和越小,可以以此将复杂度降为O(VE);
 更好的方法:首先做一步预处理,求出树上每两个结点之间的路径上的权值最大的边;
 然后枚举图中不在树上的边,有了预处理,就可以用O(1)的时间得到形成的环上的权值最大的边;
 预处理:因为是一棵树,只要简单的BFS即可,预处理所要的时间复杂度为O(V2);


#include<stdio.h>#include<string.h>#include<algorithm>#define M 107#define inf 0x3f3f3fusing namespace std;int g[M][M],path[M][M];//path求的是i到j最大的边权int dist[M],pre[M],vis[M];bool used[M][M];//是否在最小生成树中int n,m,mst;void init(){    for(int i=0;i<=n;i++)        for(int j=i+1;j<=n;j++)            g[i][j]=g[j][i]=inf;}int prime(){    int mst=0;    memset(path,0,sizeof(path));    memset(vis,0,sizeof(vis));    memset(used,0,sizeof(used));    vis[1]=1;    for(int i=1;i<=n;i++)    {        dist[i]=g[1][i];        pre[i]=1;    }    for(int i=1;i<n;i++)    {        int u=-1;        for(int j=1;j<=n;j++)        {            if(!vis[j])                if(u==-1||dist[j]<dist[u])                    u=j;        }        used[u][pre[u]]=used[pre[u]][u]=true;//加入mst        mst+=g[pre[u]][u];        vis[u]=1;        for(int j=1;j<=n;j++)        {            if(vis[j]&&j!=u)//从u到j这条路径上最大边的权值                path[j][u]=path[u][j]=max(path[j][pre[u]],dist[u]);            if(!vis[j])                if(dist[j]>g[u][j])//更新相邻节点的距离                {                    dist[j]=g[u][j];                    pre[j]=u;//记录他的前驱                }        }    }    return mst;}int second_tree()//求次小生成树{    int res=inf;    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            if(i!=j&&!used[i][j])                res=min(res,mst-path[i][j]+g[i][j]);//删除树上权值最大的路径并且加上这条路径其它边    return res;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        init();                mst=prime();//最小生成树        int second_mst=second_tree();//次小生成树    }}

最短路也有两种简单的算法。

Dijkstra算法:

#include<iostream>#include<stdio.h>#include<iomanip>using namespace std;#define N 10000#define MAX 100000099int a[N][N];int dist[N];void dijkstra(int n){    int s[N],newdist;    for(int i=1; i<=n; i++)    {        dist[i]=a[1][i];        s[i]=0;    }    dist[1]=0;    s[1]=1;    for(int i=2; i<=n; i++)    {        int j,tem=MAX;        int u=1;        for(j=2; j<=n; j++)            if(!s[j]&&dist[j]<tem)            {                u=j;                tem=dist[j];            }        s[u]=1;        for(j=2; j<=n; j++)        {            if(!s[j]&&a[u][j]<MAX)            {                newdist=dist[u]+a[u][j];                if(newdist<dist[j])                    dist[j]=newdist;            }        }    }}int main(){    int n,m;    while(scanf("%d%d",&n,&m),m||n)    {        for( i=1; i<=n; i++)        {            for(j=1; j<=n; j++)                a[i][j]=MAX;            dist[i]=MAX;        }                        dijkstra(n);        cout<<dist[n]<<endl;    }    return 0;}



Floyd算法:

#include<stdio.h>int map[105][105];int main(){    int n,m,i,j,k,a,b,c;    while(scanf("%d%d",&n,&m),n|m)    {        for(i=1;i<=n;i++)            for(j=1;j<=n;j++)                map[i][j]=10000000;                    for(k=1;k<=n;k++)            for(i=1;i<=n;i++)                for(j=1;j<=n;j++)                    if(map[i][k]+map[k][j]<map[i][j])                        map[i][j]=map[i][k]+map[k][j];        printf("%d\n",map[1][n]);    }    return 0;}















0 0
原创粉丝点击