prim算法:
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define LL long long #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 900000r #define N 1000 int n,m; int ans; int mp[N][N]; int vis[N]; struct edge { int to;//to为通向的边 int v;//为权值 friend bool operator<(const edge& a,const edge& b) { return a.v>b.v; } }now; void prim(int s) { vis[s]=1; priority_queue<edge>q; while(!q.empty())q.pop(); rep(i,1,n) { rep(j,1,n) if(!vis[j]) { now.to=j; now.v=mp[s][j]; q.push(now); } while(!q.empty()&&vis[q.top().to]) q.pop(); if(q.empty())break; now=q.top();q.pop(); s=now.to; ans+=now.v; vis[s]=1; } } int main() { CLR(vis,0); RII(n,m); rep(i,1,n) rep(j,1,n) mp[i][j]=inf; while(m--) { int a,b,c; RIII(a,b,c); a++;b++; mp[a][b]=mp[b][a]=c; } prim(1); cout<<ans<<endl; return 0; }
之前貌似学了假的prim
下面给出更加普遍的写法 和dijkstra非常相似。。。
rep(i,1,n) dis[i]=inf; dis[1]=0;int u; rep(i,1,n) { double minn=1e8; rep(j,1,n) if(!vis[j]&&dis[j]<minn) minn=dis[u=j]; ans+=minn; vis[u]=1; rep(j,1,n) if(dis[u]<dis[j])dis[j]=dis[u]; }
prim:该算法的时间复杂度为O(n2)。与图中边数无关,该算法适合于稠密图。
kruskal:需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。适合稀疏图。
第一个prim是经过堆优化过的
其实并没有优化多少 只要记得稠密图用prim 稀疏图用kruskal即可
kruskal 注意一定要大一点的数组
struct node { int s,e,v; }s[100005]; int f[N]; int n,m; int find1(int x) { return f[x]==x?x:find1(f[x]); } bool cmp(node a,node b) { return a.v<b.v; } int kruskal() { int a,b,x=1;//一开始一定要是1 int ans=0; sort(s+1,s+1+m,cmp); rep(i,1,m) { int a=find1(s[i].s); int b=find1(s[i].e); if(a==b)continue; ans+=s[i].v; f[a]=b; x++; if(x==n)return ans;//遍历了所有的点 是时候退出了 } if(x!=n)return -1;//说明没有最小生成树 else return ans; } int main() { RII(n,m); rep(i,1,n) f[i]=i; rep(i,1,m) RIII(s[i].s,s[i].e,s[i].v); printf("%d ",kruskal()); }