您的位置:首页 > 理论基础 > 数据结构算法

数据结构上机题目--MST

2013-10-28 16:38 676 查看
prim算法

/*************************************************************************
* author:crazy_石头
* algorithm:prim
* date:2013/09/29
* 程序功能:MST
* 算法流程:1.先选取一个点作起始点,然后选择它邻近的权值最小的点
(如果有多个与其相连的相同最小权值的点,随便选取一个)。如1作为起点。
   2.再在伸延的点找与它邻近的两者权值最小的点。
**************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <time.h>
#include <queue>
#include <algorithm>

using namespace std;

#define A system("pause")
#define N 100005
#define M 400010
#define INF INT_MAX
const int maxn=1000;

int dis[maxn],vis[maxn],pre[maxn];
int map[maxn][maxn];
//记录路径或者说是加入的边;

int n,e;//顶点数和边数;
int a,b;
inline int prim()
{
    int i,j,pos,res=0;
    int cnt=1;

    for(i=1;i<=n;i++)
    dis[i]=map[1][i],pre[i]=1;

    memset(vis,0,sizeof(vis));
    vis[1]=1;
    dis[1]=0;
    for(j=1;j<=n;j++)
    {
        int minm=INF;
        for(i=1;i<=n;i++)
        {
            if(!vis[i]&&minm>dis[i])
            {
                minm=dis[i];
                pos=i;//第一次找出最短距离及对应的点;
				a=i,b=pre[i];
            }
        }
        vis[pos]=1;
        if(minm==INF)
            break;
        res+=minm;
		printf("(%d,%d)\n",b,a);
        for(i=1;i<=n;i++)
        {
            if(!vis[i]&&map[pos][i]!=INF&&map[pos][i]<dis[i])
            {
                dis[i]=map[pos][i];
				pre[i]=pos;
            }
        }
    }
    return res;
}

int main()
{
    cin>>n>>e;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            i==j?map[i][j]=0:map[i][j]=INF;
        }
    }
    while(e--)
    {
        int a,b,cost;
        cin>>a>>b>>cost;
        map[a][b]=map[b][a]=cost;
    }
    int ans=prim();
    for(int i=1;i<=n;i++)
    printf("dis[%d]==%d   \n",i,dis[i]);
    printf("weight: %d\n",ans);
    return 0;
}
/*test:
6 10
1 2 6
1 4 5
1 3 1
2 3 5
2 5 3
3 5 6
3 6 4
4 6 2
5 6 6
3 4 5

output:15
*/








kruscal算法

/*************************************************************************
* author:crazy_石头
* algorithm:Kruscal
* date:2013/09/29
* 程序功能:MST
* 算法流程:初始时全为孤立的点,图的边就绪状态为非降序排列。然后一次遍历图中的所有边(u, v),
使用并查集的思想,find_set(u)如果不等于find_set(v),也就是u和v不在同一个集合中,
那么相当于判断了添加了边(u, v)不会成环,同时合并u和v(使用union_set(u, v)).
当所有的顶点都添加到集合中去了,算法完毕。
**************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <time.h>
#include <queue>
#include <algorithm>

using namespace std;

#define C system("pause")
#define INF INT_MAX
const int maxn=1000;

int p[maxn];
int n,e;

struct Edge
{
    int a;
    int b;
    int weight;
    bool operator<(const  Edge &A)const
    {
        return weight<A.weight;
    }
}edge[maxn*maxn];

inline int Find_set(int x)
{
    return p[x]==-1?x:p[x]=Find_set(p[x]);//未带路径压缩;
}

int main()
{
    int ans=0,cnt=0;
    cin>>n>>e;
    for(int i=0;i<e;i++)
    {
        cin>>edge[i].a>>edge[i].b>>edge[i].weight;
    }

    sort(edge,edge+e);
    memset(p,-1,sizeof(p));
    for(int i=0;i<e;i++)
    {
        if(cnt==n-1)
            break;

        int a=Find_set(edge[i].a);
        int b=Find_set(edge[i].b);
        printf("edge[%d].a==%d\tedge[%d].b==%d\ta==%d  b==%d,<%d,%d>edge[%d].cost==%d\n",i,edge[i].a,i,edge[i].b,a,b,a,b,i,edge[i].weight);
        if(a!=b)
        {
            cnt++;
            p[a]=b;
            ans+=edge[i].weight;//有一条边并查集找到根后,a==b,continue掉了,所以共5条边六个顶点时完成算法;
            printf("应该加入的边为<%d,%d>\n",edge[i].a,edge[i].b);
            printf("当前的ans==%d\n",ans);
        }
        else
            continue;
    }
    printf("%d\n",ans);
    return 0;
}
/*test:
6 10
1 2 6
1 4 5
1 3 1
2 3 5
2 5 3
3 5 6
3 6 4
4 6 2
5 6 6
3 4 5

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