模板——最小生成树prim算法&&向前星理解
通过最小生成树(prim)和最短路径优化引出的向前星存图,时至今日才彻底明白了。。
head[i]存储的是父节点为i引出的最后一条边的编号,
next负责把head[i]也就是i作为父节点的所有边连接起来,next也是存的编号,
在所存的edge结构体中,只有w是保存边的值,而u是保存的子节点。
这样设置的话,由head[i]就可以引出所有与i相关的边和点,
显而易见,这样的存放方法空间+时间复杂度双优化,比邻接矩阵是优化多了。。
然后就是prim算法,
最小生成树的一种算法,适用于稠密图,因为是以点更新的,正好与之前的克鲁斯卡尔算法互补了,
不过代码比k长,思路也难一些,大致和迪杰差不多,也用了dis数组,目测也就是更新dis值的时候不同(其实很不同,就形式差不多而已),
下面附上代码,借鉴某位luogu大神的题解,真的很简洁明了了,在luogu上比 k 快了大概一倍240+ms。
其他优化用了快读+re。
1 #include <iostream> 2 #include <string> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 #define maxn 5002 7 #define maxm 200001 8 #define inf 9999 9 #define re register 10 11 using namespace std; 12 13 int n,m,cnt,sum=0,k=0; 14 int a,b,c; 15 int dis[maxn],head[maxn],vis[maxn]; 16 17 typedef pair <int,int> pii; 18 priority_queue <pii,vector<pii>,greater<pii> > q; 19 20 struct Edge 21 { 22 int w,next,v;//w权值,v子节点 23 }edge[maxm*2]; 24 inline int read() 25 { 26 char ch; 27 int a=0; 28 while(!(((ch=getchar())>='0')&&(ch<='9'))); 29 a*=10;a+=ch-'0'; 30 while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0'; 31 return a; 32 } 33 void add(int u,int v,int w) 34 { 35 edge[++cnt].v=v; 36 edge[cnt].w=w; 37 edge[cnt].next =head[u]; 38 head[u]=cnt; 39 } 40 41 void prim() 42 { 43 dis[1]=0; 44 q.push(make_pair(0,1)); 45 while(!q.empty()&&k<n) 46 { 47 int d=q.top().first,u=q.top().second;//first 最小值,second 位置 48 q.pop(); 49 if(vis[u])continue; 50 k++; 51 sum+=d; 52 vis[u]=1; 53 for(re int i=head[u];i!=-1;i=edge[i].next ) 54 { 55 if((edge[i].w<dis[edge[i].v])) 56 { 57 dis[edge[i].v]=edge[i].w; 58 q.push(make_pair(dis[edge[i].v],edge[i].v)) ; 59 } 60 } 61 } 62 } 63 64 int main() 65 { 66 memset(head,-1,sizeof(head)); 67 memset(dis,inf,sizeof(dis)); 68 n=read(); 69 m=read(); 70 for(re int i=1;i<=m;i++) 71 { 72 a=read();b=read();c=read(); 73 add(a,b,c); 74 add(b,a,c); 75 } 76 prim(); 77 if(k==n)printf("%d",sum); 78 else cout<<"orz"; 79 return 0; 80 }
————————————————————————————————
执笔饰年华,一笑叹天涯。逢春即润物,生当得潇洒。