并查集和prime和kruskal

现在有10个强盗,下面9行两个人是一个团伙
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
求有几个团伙

//并查集
#include<stdio.h>
int f[1000]={0},n,m,k,sum=0;
//第一步,这里是初始,非常的重要,数组里面存自己的下标就好了(自己是自己的老大)
void init()
{
    int i;
    for(i=1;i<=n;i++)
        f[i]=i;
    return ;
}
//这是找爹的递规函数,不停的去找爹,直到找到祖宗为止,其实就是去犯罪团伙的最高领导,“擒贼先擒王”原则
int getf(int v)
{
    if(f[v]==v)
        return v;
    else
    {
        f[v]=getf(f[v]);//找爹循环,哈哈哈
        return f[v];//返回找到的值
    }
}
//这里是合并两子集合的函数
void merge(int v,int u)
{
    int t1,t2;
    t1=getf(v);//注意这里是getf(v),不是getf(f[v]),要不然就隔过了一层找爹循环
    t2=getf(u);
    if(t1!=t2)//判断两节点是否同一祖先
    {
    //靠左原则
        f[t2]=t1;
    }
    return ;
}
int main()
{
    int i,x,y;
    scanf("%d%d",&n,&m);
    //初始化为第一步
    init();
    //第二步合并团伙,题型可能有改动,但是万变不离其宗
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        merge(x,y);
    }   
    //第三步扫描有多少团伙
    for(i=1;i<=n;i++)
    {
        if(f[i]==i)
            sum++;
    }
    printf("%d
",sum);
    getchar();getchar();
    return 0;
}
//答案为3

有好几个孤岛,要把它们连起来,且花费最少
数据
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
找到n-1条边,使得n个岛连通且路程最短

//最小生成树kruskal算法
//核心:排序,选用n-1条边
#include <stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct edge
{
    int u,v,w;
}e[10];
int cmp(edge x,edge y)
{
    return x.w<y.w;
}
int n,m;
int f[7]={0},sum=0,cou=0;
int geft(int v)
{
    if(f[v]==v)
        return v;
    else
    {
        f[v]=geft(f[v]);
        return f[v];
    }
}
int merge(int v,int u)
{
    int t1,t2;
    t1=geft(v);
    t2=geft(u);
    if(t1!=t2)
    {
        f[t2]=t1;
        return 1;
    }
    return 0;
}
int main()
{
    int i;
    scanf("%d%d",&n,&m);
    //第一步,找到一个结构体储存边的位置
    for(i=1;i<=m;i++)
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    //第二步,按边的大小排序    
    sort(e+1,e+m+1,cmp);
    //第三步,初始化
    for(i=1;i<=n;i++)
        f[i]=i;
    //第四步,kruskal算法的核心    
    for(i=1;i<=m;i++)
    {
    //先判断两点是否连通
        if(merge(e[i].u,e[i].v))//如果不连通,这条边
        {
            cou++;  
            sum=sum+e[i].w;
        }
        if(cou==n-1)//直到n-1条边后退出循环
            break;
    }
    printf("%d",sum);//打印结果
    getchar();getchar();
    return 0;
}

这个算法也采用上面那个例子;
这个算法的思想是:

//prime算法
#include<stdio.h>
int main()
{
    int n,m,i,j,k,minn,t1,t2,t3;
    int e[7][7],dis[7],book[7]= {0};//这里对book数组进行初始化
    int inf=999999999;//用inf(infinity的缩写)储存一我们认为的正无穷值
    int cou=0,sum=0;//cou用来生成树中定点的,sum用来路径之和;
    //读入n和m,n表示定点个数,m表示边的条数
    scanf("%d%d",&n,&m);
    //第一步,初始化
    for(i=1; i<=n; i++)
        for(j=1; j<=n; j++)
            if(i==j)
                e[i][j]=0;
            else
                e[i][j]=inf;
    //第二步,读入边
    for(i=1; i<=m; i++)
    {
        scanf("%d%d%d",&t1,&t2,&t3);
        e[t1][t2]=t3;
        e[t2][t1]=t3;
    }
    //第三步,初始化dis数组,
    for(i=1; i<=n; i++)
        dis[i]=e[1][i];
    //第四步,将一号点加入树    
    book[1]=1;
    //第五步,加边
    cou++;
    //第六步,prime算法核心
    while(cou<n)//找到n-1条边
    {
        minn=inf;
        for(i=1; i<=n; i++)
        {
            if(book[i]==0&&dis[i]<minn)//找下一个能走的点
            {
                minn=dis[i];
                j=i;
            }
        }
        book[j]=1;
        cou++;
        sum=sum+dis[j];
        for(k=1; k<=n; k++)
        {
            if(book[k]==0&&dis[k]>e[j][k])//找到通向这个点的最短路
                dis[k]=e[j][k];
        }
        //扫描当前定点j所有边,在以j为中间点,更新生成树到每一个非数定点的距离
        for(k=1;k<=n;k++)
        {
            printf("%d ",dis[k]);
        }
        printf("
");
    }
    printf("%d",sum);//打印结果
    getchar();
    getchar();
    return 0;
}
"No regrets."
原文地址:https://www.cnblogs.com/zxy160/p/7215154.html