Prim算法O(n^2,n为点数):
说明:先任意找一个点标记,然后每次找一条最短的两端分别为标记和未标记的边加进来,再把未标记的点标记上。即每次加入一条合法的最短的边,每次扩展一个点由未标记为已标记,直至扩展为N个点。
HDU1233
我的代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #include<string.h> #define MAX 100000000 int map[101][101],visit[101]; /*map[x][y]记录x点到y点的距离,visit[],记录点是否标记。*/ long long prim(int n); int main() { int n; while(scanf("%d",&n)&&n) { int m = n*(n-1)/2; int i,j,a,b,c; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(i==j) map[i][j] = 0; else map[i][j]=map[j][i]=MAX; } } for(i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); map[a][b]=map[b][a]=c; /*初始完map[][]*/ } long long ans = prim(n); printf("%lld\n",ans); } return 0; } long long prim(int n) { long long ans = 0; int minimal[510],i,j,min,k; memset(minimal,0,sizeof(minimal)); memset(visit,0,sizeof(visit)); visit[1] = 1; /*从1开始,标记1*/ for(i=1;i<=n;i++) minimal[i] = map[1][i]; /*得到从开始点到其它个点的距离。*/ for(i=1;i<n;i++) { min = MAX; for(j=1;j<=n;j++) { if(minimal[j]<min&&visit[j]==0) { min = minimal[j]; /*得到其它未标记点到标记点的最短距离。*/ k = j; /*得到最短距离的未标记点*/ } } ans += min; visit[k] = 1; /*把未标记点标记*/ for(j=1;j<=n;j++) { if(minimal[j]>map[k][j]&&visit[j]==0&&k!=j) { minimal[j] = map[k][j]; /*重新初始其它未标记点到标记点的距离,若其它未标记点到新标记点k的距离更短则替换。*/ } } } return ans; }
Kruskal算法O(mlogm,m为边数):
说明:Kruskal是通过一个贪心的想法:每次取剩下的边权最小的边,如果加上这条边以后图中出现一个环,则破坏生成树的性质,就不选这条边。依次进行直到整张图出现一颗生成树为止。
HDU1233
我的代码:
hdu oj里的G++好像不支持二维数组排序,这个代码不能过
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #define N 105 int set[N]; int comp(const void *a,const void *b); long long as(int sz[][3],int n,int a); int fine(int a); int main() { int n; while(scanf("%d",&n)&&n) { int m = n*(n-1)/2; int sz[m][3],i; for(i=0;i<m;i++) { scanf("%d%d%d",&sz[i][0],&sz[i][1],&sz[i][2]); } for(i=0;i<N;i++) set[i] = i; qsort(sz,m,sizeof(int)*3,comp); long long ans = as(sz,m,n); printf("%lld\n",ans); } return 0; } int comp(const void *a,const void *b) { return ((int *)a)[2]-((int *)b)[2]; } int fine(int a) { return a==set[a] ? a : (set[a]=fine(set[a])); } long long as(int sz[][3],int n,int a) { long long ans = 0; int i; for(i=0;i<n;i++) { if(fine(sz[i][0])!=fine(sz[i][1])) { set[fine(sz[i][1])] = fine(sz[i][0]); ans += sz[i][2]; a--; if(a==1) break; } else continue; } return ans; }
重新把二维数组排序写成函数后就可以过了。
我的代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #define N 105 int set[N]; void qsort(int sz[][3],int a); /*二维数组排序的函数*/ long long as(int sz[][3],int n,int a); int fine(int a); int main() { int n; while(scanf("%d",&n)&&n) { int m = n*(n-1)/2; int sz[m][3],i; for(i=0;i<m;i++) { scanf("%d%d%d",&sz[i][0],&sz[i][1],&sz[i][2]); } for(i=0;i<N;i++) set[i] = i; qsort(sz,m); /*按边排序*/ long long ans = as(sz,m,n); printf("%lld\n",ans); } return 0; } void qsort(int sz[][3],int a) { int i,j,x,exchange; for(i=0;i<a-1;i++) { for(j=i+1;j<a;j++) { if(sz[i][2]>sz[j][2]) { for(x=0;x<3;x++) { exchange = sz[i][x]; sz[i][x] = sz[j][x]; sz[j][x] = exchange; } } } } } int fine(int a) { return a==set[a] ? a : (set[a]=fine(set[a])); } long long as(int sz[][3],int n,int a) { long long ans = 0; int i,j; for(i=0;i<n;i++) { if(fine(sz[i][0])!=fine(sz[i][1])) /*连接该边不构成环*/ { set[fine(sz[i][1])] = fine(sz[i][0]); ans += sz[i][2]; j++; if(j==a-1) break; /*边数==点数-1即生成树完成。*/ } } return ans; }