最小生成树 Prim、Kruscal算法 (以HDU 1863为例)
来源:互联网 发布:python基础语句 编辑:程序博客网 时间:2024/06/15 04:38
畅通工程
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 32680 Accepted Submission(s): 14407
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
3 31 2 11 3 22 3 41 32 3 20 100
3?
(u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,(u,v)为其中一条边。
两种求解方式及其复杂度: Prim算法,邻接矩阵时间复杂度O(n^2),邻接表时间复杂度O(mlog2n);Kruskal算法时间复杂度O(mlogm)。n为点的个数,m为边的条数。
Prim算法
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
具体实现:以任意点为顶点,找到此点所有可以到达的点,标记当前顶点,找到可到达的点最近的顶点标记,将此顶点可到达的顶点加入数组,用来再去找可以路径最短的,直到标记所有的点为止,最后输出sum。
代码模板:(邻接矩阵)
#include<iostream> #include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<cstdio>#include<set>#define ll long long#define mset(a,x) memset(a,x,sizeof(a))using namespace std;const double PI=acos(-1);const int inf=0x3f3f3f3f;const double esp=1e-6;const int maxn=105;const int mod=1e9+7;int dir[4][2]={0,1,1,0,0,-1,-1,0};ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}ll lcm(ll a,ll b){return a/gcd(a,b)*b;}ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}int map[maxn][maxn],visit[maxn],dis[maxn],n,m; //n代表边数,m代表点数,map存路径,dis存当前点到下一点距离,visit标记 void init(){int i;mset(visit,0);mset(map,inf);for(i=0;i<=maxn;i++)map[i][i]=0;}void prim(int s){int i,j,k;for(i=1;i<=m;i++) //赋初值 dis[i]=map[s][i];visit[s]=1;for(i=2;i<=m;i++){int minn=inf;k=0;for(j=1;j<=m;j++){if(!visit[j]&&minn>dis[j]){minn=dis[j];k=j;}}visit[k]=1;for(j=1;j<=m;j++) //更新 {if(!visit[j]&&dis[j]>map[k][j])dis[j]=map[k][j];}}}int main(){int i,j,k,x,y,z;while(~scanf("%d%d",&n,&m)){if(n==0)break;init();for(i=0;i<n;i++){cin>>x>>y>>z;if(map[x][y]>z){map[x][y]=map[y][x]=z;}}prim(1);int flag=1;for(i=1;i<=m;i++)if(dis[i]==inf)flag=0;if(flag){int ans=0;for(i=1;i<=m;i++)ans+=dis[i];printf("%d\n",ans);}elsecout<<"?"<<endl;}return 0;}
邻接表
#include <iostream>#include <queue>#include <algorithm> #include <string.h>#include <math.h>using namespace std;const int maxx=200;const int maxn=1e4+10;const int inf=0x3f3f3f3f;int sum,ans,m,n,q;struct point {int next;int to;int val;bool operator < (const point &a) const{return val>a.val; } };point pt[2*maxn];bool vis[maxx];int dis[maxx],head[2*maxn];void add(int u,int v,int val){pt[q].next=head[u];pt[q].val=val;pt[q].to=v;head[u]=q++;}void prim(int st){priority_queue<point>q;point t1,t2;ans=1,sum=0;memset(vis,false,sizeof(vis));memset(dis,inf,sizeof(dis));for (int i=head[st];i!=-1;i=pt[i].next){int v=pt[i].to;if (pt[i].val<dis[v]){dis[v]=pt[i].val;t1.to=v;t1.val=dis[v];q.push(t1);}}vis[st]=true;while (!q.empty()){t1=q.top();q.pop();int v=t1.to;if (vis[v])continue;vis[v]=true;sum+=dis[v];ans++;for (int i=head[v];i!=-1;i=pt[i].next){int u=pt[i].to;if (!vis[pt[i].to]&&pt[i].val<dis[u]){dis[u]=pt[i].val;t2.to=pt[i].to;t2.val=dis[u];q.push(t2);}}}}int main(){int u,v,val,st; while(~scanf("%d%d",&n,&m)) { if (n==0) break; q=1; memset(head,-1,sizeof(head)); for (int i=0;i<n;i++) { scanf("%d%d%d",&u,&v,&val); add(u,v,val); add(v,u,val); st=u;}prim(st);if (ans==m)printf("%d\n",sum);elseprintf("?\n"); } return 0; }
Kruscal算法
1).记Graph中有v个顶点,e个边
2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
3).将原图Graph中所有e个边按权值从小到大排序
4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中
if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中
添加这条边到图Graphnew中
具体实现:将边的权值经行排序,从最小的边开始添加,每次都加入最小的边,运用并查集,最后得到结果。代码模板:
#include<iostream> #include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<cstdio>#include<set>#define ll long long#define mset(a,x) memset(a,x,sizeof(a))using namespace std;const double PI=acos(-1);const int inf=0x3f3f3f3f;const double esp=1e-6;const int maxn=105;const int mod=1e9+7;int dir[4][2]={0,1,1,0,0,-1,-1,0};ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}ll lcm(ll a,ll b){return a/gcd(a,b)*b;}ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}struct edge{int s,t;int len;}p[maxn*maxn];int pre[1005];int n,m;int cmp(edge a,edge b){return a.len<b.len;}int find(int x){if(pre[x]==x)return x;return pre[x]=find(pre[x]);}int main(){int i,j,k,x,y,z;while(~scanf("%d%d",&n,&m)&&n){for(i=1;i<=m;i++)pre[i]=i;for(i=0;i<n;i++){cin>>x>>y>>z;p[i].s=x;p[i].t=y;p[i].len=z;}sort(p,p+n,cmp);int ans=0,count=0;for(i=0;i<n&&count<m-1;i++){int fx=find(p[i].s);int fy=find(p[i].t);if(fx!=fy){pre[fx]=fy; ans+=p[i].len; count++;}}if(count==m-1)cout<<ans<<endl;elsecout<<"?"<<endl;}return 0;}
- 最小生成树 Prim、Kruscal算法 (以HDU 1863为例)
- 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)
- 最小生成树(prim和kruscal算法)
- HDU 1863 畅通工程 (最小生成树--Kruscal、Prim)
- 最小生成树 prim kruscal
- 最小生成树的prim算法和kruscal算法
- HDU 1233最小生成树 Kruscal 算法
- 最小生成树(Prim和Kruscal)
- 最小生成树之PRIM及KRUSCAL
- 修路问题-最小生成树 Prim&Kruscal
- 最小生成树(先写个prim,kruscal)
- kruscal最小生成树算法
- 最小生成树-Kruscal算法
- 最小生成树算法---Kruscal算法和Prim算法(入门)
- hdu 1233 最小生成树Prim算法
- HDU-1233 最小生成树 Prim算法
- HDU 1863 畅通工程(最小生成树prim算法)
- HDU - 1863 - 畅通工程 (最小生成树!!prim算法!!)
- php封装单文件上传到数据库(路径)
- <学习笔记?>考试与做题的注意事项总结。
- zookeeper 安装
- Linux的find、grep命令
- android的IPC机制
- 最小生成树 Prim、Kruscal算法 (以HDU 1863为例)
- 站外跳转到谷歌地图
- webwork+spring+hibernate的整合
- java中怎么将本地图片上传到服务器上
- Ubuntu16.04安装CUDA8.0+Cudnn V6+Caffe+TensorFlow+Faster RCNN --> 1080ti+X99主板
- kubernetes client-go
- LA3177
- MAC无法安装ruby-debug-ide gems包(ERROR: Failed to build gem native extension)的解决办法
- 嵌入式开发中三种操作系统的分析与比较