1.知识点复习:并查集,最小生成树(prime和克鲁斯卡尔)算法.
并查集
void init(int x)//初始化 { for(int i=1;i<=x;i++) { f[i]=i; rank[i]=1; } } int find(int x) { if(x==f[x]) return x; else {//路径压缩 f[x]=find(f[x]); return f[x]; } /*非路径压缩 else{ return find(f[x]); } */ } //按序合并 void merge(int x,int y) { int n=find(x),m=find(y); if(rank[n]==rank[m]) { f[m]=n;rank[n]++; } if(rank[n]>rank[m]){ f[m]=n; } else f[n]=m; } //按序合并与路径压缩一般不一起用。 void merge1(int x,int y) { int n=find(x),m=find(y); f[n]=m; }
克鲁斯卡尔算法写最小生成树要用到并查集(数据大时一定要用路径压缩)。
prime算法模板
int prime(int n,int st) { int cnt=st; vis[st]=1;//标记起点并记录他 for(int i=1;i<=n;i++) { if(i==st) dis[st]=0; else dis[i]=mp[i][st]; } //更新dis for(int i=1;i<n;i++)//再找接下来的n个点 { int mini=min_n; for(int j=1;j<=n;j++)//找到目前未归类的最短路径连接的点 { if(vis[j]==0&&mini>dis[j]) { mini=dis[j]; cnt=j; } } ans+=dis[cnt]; vis[cnt]=1; for(int j=1;j<=n;j++)//更新路径 if(vis[j]==0&&dis[j]>mp[cnt][j])//以目前找到的点为起点更新dis dis[j]=mp[cnt][j]; /*迪杰斯特拉 if(vis[j]==0&&dis[j]>mp[cnt][j]+dis[cnt]) dis[j]=mp[cnt][j]+dis[cnt]; */ } }
由于prime算法与迪杰斯特拉思路相似,重新写一下思路复习两个算法。将已经连接的点与未连接的点设定两个集合,用vis[ ]数组标记是否找到,vis[]=1表示找到。每次从vis[]=0的集合里找到一个距离vis[]=1集合最近的点,并更新dis[].迪杰斯特拉与prime算法的不同处就在于更新dis的操作。
用线段树完成动态最小生成树