并查集和prime和kruskal

    xiaoxiao2021-03-25  101

    现在有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; }
    转载请注明原文地址: https://ju.6miu.com/read-5390.html

    最新回复(0)