生成最小生成树的Kruakal算法
Kruakal算法只与边有关,适用于稀疏图。
算法思想:
难点在于判断回路是否形成。
看是否有回路这里主要是使用并查集的方法判断,如果加入的点有回路则边的两点有共同的父节点。即find[x]==find[y].
并查集代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int fa[maxn]; void init(int n) { for(int i=0;i<=n;i++) fa[i]=i; }
int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
void merge(int i,int j) { fa[find(i)]=find(j); }
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include<iostream> #include<algorithm> #include<time.h> #include<cmath> #include<vector> #define maxn 1024 using namespace std; long long n,matrix[maxn][maxn],fa[maxn],sum=0,len=0;
void rand_seed() { int seed = static_cast<int>(time(0)); srand(seed); }
struct GVE { int x,y,w; }G[maxn];
int cmp(GVE a,GVE b) { if(a.w!=b.w) return a.w>b.w; else return a.x>b.x; }
class init { public: void create() { cout<<"输入n:"; cin>>n; for(int i=0;i<n;i++) for(int j=0;j<n;j++) matrix[i][j]=maxn; for(int i=0;i<n;i++) { if(i==0) { matrix[i][1]=rand()%n+1; matrix[i][2]=rand()%n+1; } else for(int j=i+1;j<n;j++) matrix[i][j]=rand()%n+1; } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(matrix[i][j]!=maxn) { G[len].x=i; G[len].y=j; G[len].w=matrix[i][j]; len++; } } } } };
void Finit() { for(int i=0;i<n;i++) fa[i]=i; } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void merge(int x,int y) { fa[find(x)]=find(y); }
void print() { cout<<n<<"*"<<n<<"阶的邻接矩阵:"<<endl; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) if(matrix[i][j]==maxn) cout<<"m"<<" "; else cout<<matrix[i][j]<<" "; cout<<endl; } }
void kruakal() { int x,y,w; vector<int> T[3]; while(T[0].size()<n-1) { len--; x=find(G[len].x); y=find(G[len].y); w=G[len].w; if(x!=y) { T[0].push_back(x); T[1].push_back(y); T[2].push_back(w); sum+=w; merge(x,y); } } cout<<"通过kruakal算法得到的最小生成树:"<<endl; for(int i=0;i<n-1;i++) { printf("边:(%d,%d) 权值:%d\n",T[0][i],T[1][i],T[2][i]); } cout<<"权值和:"<<sum;
}
int main() { init M; rand_seed(); M.create(); Finit(); print(); cout<<endl; sort(G,G+len,cmp);
kruakal(); }
|
运行结果
经典案列
代码修饰后运行结果:
生成最小生成树prim算法
prim算法只与点有关,适用于点较少的稠密矩阵。
算法思想:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
| #include<iostream> #include<time.h> #define maxn 1024 using namespace std; long long matrix[maxn][maxn],n; void rand_seed() { int seed = static_cast<int>(time(0)); srand(seed); } struct GVE { int x,y,w; }G[maxn]; class init { public: void create() { cout<<"输入n:"; cin>>n; for(int i=0;i<n;i++) for(int j=0;j<n;j++) matrix[i][j]=maxn; for(int i=0;i<n;i++) { if(i==0) { matrix[i][1]=rand()%n+1; matrix[i][2]=rand()%n+1; } else for(int j=i+1;j<n;j++) matrix[i][j]=rand()%n+1; } for(int i=0;i<n;i++) { for(int j=0;j<i;j++) { matrix[i][j]=matrix[j][i]; } } } };
void print() { cout<<n<<"*"<<n<<"阶的邻接矩阵:"<<endl; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) if(matrix[i][j]==maxn) cout<<"m"<<" "; else cout<<matrix[i][j]<<" "; cout<<endl; } } void perm() { cout<<"出发顶点:"; int x,g=0; cin>>x; int X[maxn],Y[maxn],C1[maxn],C2[maxn]; X[0]=x; for(int i=0;i<n;i++) Y[i]=i; for(int i=0;i<n;i++) { if(i==x) { for(int k=i;k<n-1;k++) Y[k]=k+1; break; } } int len=n-1; for(int i=0;i<n;i++) { C1[i]=x; C2[i]=maxn; } while(len!=0) { for(int i=0;i<len;i++) { if(matrix[x][Y[i]]!=maxn) { int b=matrix[x][Y[i]]; if(b<C2[Y[i]]) { C2[Y[i]]=b; C1[Y[i]]=x; } } } int minx=C2[Y[0]],u=0; for(int i=1;i<len;i++) { if(minx>C2[Y[i]]) minx=C2[Y[i]]; } for(int i=0;i<len;i++) { if(minx==C2[Y[i]]) { u=i; break; } } int z=C1[Y[u]]; G[g].x=Y[u]; G[g].y=z; G[g].w=minx; g++; X[n-len]=Y[u]; x=Y[u]; C2[Y[u]]=maxn; for(int i=u;i<len-1;i++) Y[i]=Y[i+1]; len--; } for(int i=0;i<g;i++) { printf("边 (%d,%d)",G[i].x,G[i].y); printf(" 权值:%d \n",G[i].w); } } int main() { init M; rand_seed(); M.create(); print(); perm(); return 0; }
|
运行结果:
单元最短路径问题
算法思想:
实现:
伪代码:
输入: 一个大于1的整数n.
输出: 一个随机生成的有向图G=(V,E),对于每一条边,有一个非负数字c(u,v)与之相关。
对于每个顶点v∈V,得到从v_0 到v的最短路径的长度。
程序运行时间。
步骤1: 随机生成一个有向图G=(V,E),用rand_seed()函数使得每一次程序运行时随机生成的有向图都不同。
步骤2: 令S=0,V_S=V-v_0。
步骤3: 将与v_0相连接的点v_i的值c赋值给L(v_i),其余将∞赋值给L(v_i)。
步骤4: 从V_S中选出u使得L(u)是最小的,将u从V_S删除,S=S∪{u}。
步骤5: 对于V_S中的所有点w使得L(w)=min(L(w),L(u)+c(u,w)),返回步骤4.
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| #include<iostream> #include<time.h> #include<Windows.h> #define maxn 1024 using namespace std; long long n,matrix[maxn][maxn]; long long L[maxn],S[maxn],V_S[maxn];
void rand_seed() { int seed = static_cast<int>(time(0)); srand(seed); } class init { public: void create() { cout<<"输入n:"; cin>>n; for(int i=0;i<n;i++) for(int j=0;j<n;j++) matrix[i][j]=maxn; for(int i=0;i<n;i++) { if(i==0) { matrix[i][1]=rand()%n; matrix[i][2]=rand()%n; } else for(int j=i+1;j<n;j++) matrix[i][j]=rand()%n; } } }; void print() { cout<<n<<"*"<<n<<"阶的邻接矩阵:"<<endl; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) if(matrix[i][j]==maxn) cout<<"m"<<" "; else cout<<matrix[i][j]<<" "; cout<<endl; } } void look_min(int l) { int minx=L[V_S[0]]; for(int i=0;i<l;i++) { if(L[V_S[i]]<minx) minx=L[V_S[i]]; } int u=0; for(int i=0;i<l;i++) { if(L[V_S[i]]==minx) { u=V_S[i]; S[n-l-1]=i; for(int k=i;k<l-1;k++) V_S[k]=V_S[k+1]; l--; break; } } for(int k=0;k<l;k++) { L[V_S[k]]=min(L[V_S[k]],L[u]+matrix[u][V_S[k]]); } }
int main() { double start = GetTickCount(); init M; rand_seed(); M.create(); for(int i=1;i<n;i++) { V_S[i-1]=i; } for(int i=1;i<n;i++) { if(matrix[0][i]!=maxn) L[i]=matrix[0][i]; else L[i]=maxn; } for(int i=0;i<n;i++) { look_min(n-i-1); } double stop = GetTickCount(); print(); cout<<endl; cout<<"最短路径:"<<endl; for(int i=1;i<n;i++) cout<<"从顶点v0出发到V"<<i<<"的最短路径为: "<<L[i]<<endl; cout<<endl<<"程序运行所需时间:"<<stop-start<<" ms"; return 0; }
|
结果:
其他的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
#include<iostream> #include<cmath> #include<algorithm> #define maxn 10000 #define m 10000 using namespace std; int n; double array[maxn][maxn]; double L[m]={0}; int V[m]={0},S[m]={0}; double cost(int x1,int y1,int h1,int x2,int y2,int h2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))+(h1-h2)*(h1-h2); } void prin() { for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(array[i][j]!=m) cout<<array[i][j]<<" "; else cout<<"m "; } cout<<endl; } } void Dijkstra() { S[0]=0; for(int i=0;i<n-1;i++) V[i]=i+1; L[0]=m; for(int i=1;i<n;i++) { if(array[0][i]!=m) L[i]=array[0][i]; else L[i]=m; } for(int i=1;i<n;i++) { int len=n-i,u=0; double minx=L[V[0]]; for(int k=1;k<len;k++) { if(minx>L[V[k]]) minx=L[V[k]]; } for(int k=0;k<len;k++) { if(minx==L[V[k]]) { u=V[k]; S[i]=u; for(int j=k;j<len-1;j++) V[j]=V[j+1]; break; } } for(int k=0;k<len-1;k++) L[V[k]]=min(L[V[k]],L[u]+array[u][V[k]]); } } int main() { cin>>n; int x[n],y[n],h[n]; for(int i=0;i<n;i++) cin>>x[i]>>y[i]>>h[i]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(j>i) { array[i][j]=cost(x[i],y[i],h[i],x[j],y[j],h[j]); } else array[i][j]=m; } } prin(); Dijkstra(); for(int i=1;i<n;i++) cout<<"v0到"<<"v"<<i<<"的单源最短路径为: "<<L[i]<<endl; return 0; }
|
最终版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| #include<iostream> #include<time.h> #include<Windows.h> #define maxn 5000 using namespace std; long long n,matrix[maxn][maxn]; long long L[maxn],S[maxn],V_S[maxn];
void rand_seed() { int seed = static_cast<int>(time(0)); srand(seed); } class init { public: void create(int n) {
for(int i=0;i<n;i++) for(int j=0;j<n;j++) matrix[i][j]=maxn; for(int i=0;i<n;i++) { if(i==0) { matrix[i][1]=rand()%n; matrix[i][2]=rand()%n; } else for(int j=i+1;j<n;j++) matrix[i][j]=rand()%n; } } }; void print() { cout<<n<<"*"<<n<<"阶的邻接矩阵:"<<endl; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) if(matrix[i][j]==maxn) cout<<"m"<<" "; else cout<<matrix[i][j]<<" "; cout<<endl; } } void look_min(int l) { int minx=L[V_S[0]]; for(int i=0;i<l;i++) { if(L[V_S[i]]<minx) minx=L[V_S[i]]; } int u=0; for(int i=0;i<l;i++) { if(L[V_S[i]]==minx) { u=V_S[i]; S[n-l-1]=i; for(int k=i;k<l-1;k++) V_S[k]=V_S[k+1]; l--; break; } } for(int k=0;k<l;k++) { L[V_S[k]]=min(L[V_S[k]],L[u]+matrix[u][V_S[k]]); } }
int main() {
cout<<"输入n:"; cin>>n; init M; rand_seed(); M.create(n); LARGE_INTEGER nFreq; LARGE_INTEGER nBeginTime; LARGE_INTEGER nEndTime; QueryPerformanceFrequency(&nFreq); QueryPerformanceCounter(&nBeginTime);
for(int i=1;i<n;i++) { V_S[i-1]=i; } for(int i=1;i<n;i++) { if(matrix[0][i]!=maxn) L[i]=matrix[0][i]; else L[i]=maxn; } for(int i=0;i<n;i++) { look_min(n-i-1); } QueryPerformanceCounter(&nEndTime);
print(); cout<<endl; cout<<"最短路径:"<<endl; for(int i=1;i<n;i++) cout<<"从顶点v0出发到V"<<i<<"的最短路径为: "<<L[i]<<endl; double time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart; cout<<"程序运行所需时间:"; cout<<time*1000<<" ms"<<endl; return 0; }
|