并查集和prime和kruskal

来源:互联网 发布:软件公寓如何申请 编辑:程序博客网 时间:2024/05/04 16:54

现在有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\n",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("\n");    }    printf("%d",sum);//打印结果    getchar();    getchar();    return 0;}
1 0
原创粉丝点击