MST最小生成树
首先,贴上一个很好的讲解贴:
http://www.wutianqi.com/?p=3012
HDOJ 1233 还是畅通工程
http://acm.hdu.edu.cn/showproblem.php?pid=1233
裸的Prim...
- #include<cstdio>
- #define MAXN 105
- #define INF 0x3f3f3f3f
- int map[MAXN][MAXN];
- int dist[MAXN];
- int vis[MAXN];
- int n,a,b,x,ans,tot;
- void init()
- {
- for(int i=;i<=n;i++)
- {
- for(int j=;j<=n;j++)
- {
- if(i==j) map[i][j]=;
- else map[i][j]=INF;
- }
- vis[i]=;
- dist[i]=INF;
- }
- }
- void Prim()
- {
- tot=;ans=;
- for(int i=;i<=n;i++)
- {
- if(map[][i]<INF)
- dist[i]=map[][i];
- }
- vis[]=;
- int tmp,u=,flag;
- for(int i=;i<=n;i++)
- {
- tmp=INF;flag=;
- for(int j=;j<=n;j++)
- {
- if(!vis[j]&&dist[j]<tmp)
- {
- flag=;
- tmp=dist[j];
- u=j;
- }
- }
- vis[u]=;
- if(flag) ans+=dist[u];
- for(int j=;j<=n;j++)
- {
- if(!vis[j]&&map[u][j]<dist[j])
- dist[j]=map[u][j];
- }
- }
- }
- int main()
- {
- while(scanf("%d",&n)!=EOF)
- {
- if(n==) break;
- init();
- for(int i=;i<n*(n-)/;i++)
- {
- scanf("%d%d%d",&a,&b,&x);
- if(map[a][b]>x)//可能有重边,要取最小的,开始没加这个WA
- {
- map[a][b]=x;
- map[b][a]=x;
- }
- }
- Prim();
- printf("%d\n",ans);
- }
- return ;
- }
HDOJ 1863 畅通工程
http://acm.hdu.edu.cn/showproblem.php?pid=1863
遇见水题心情大好,哟哟切克闹,Kruskal、Prim各一套...
- #include<cstdio>
- #include<queue>
- #define MAXN 105
- using namespace std;
- int father[MAXN];
- int find(int x)
- {
- return father[x]==x?x:father[x]=find(father[x]);
- }
- int merge(int a,int b)
- {
- int fa=find(a);
- int fb=find(b);
- if(fa!=fb)
- {
- father[fa]=fb;
- return ;
- }
- return ;
- }
- struct line
- {
- int x,y,w;
- friend bool operator<(line a,line b)
- {
- return a.w>b.w;
- }
- };
- line tmp;
- priority_queue<line> q;
- int n,m,a,b,x,ans,tot;
- int Kruskal()
- {
- tot=;
- ans=;
- while(!q.empty())
- {
- tmp=q.top();
- q.pop();
- if(merge(tmp.x,tmp.y))
- {
- tot++;
- ans+=tmp.w;
- if(tot==n-) return ;
- }
- }
- return ;
- }
- void init()
- {
- for(int i=;i<=n;i++)
- {
- father[i]=i;
- }
- while(!q.empty()) q.pop();
- }
- int main()
- {
- while(scanf("%d%d",&m,&n)!=EOF)
- {
- if(m==) break;
- init();
- for(int i=;i<m;i++)
- {
- scanf("%d%d%d",&a,&b,&x);
- tmp.x=a;
- tmp.y=b;
- tmp.w=x;
- q.push(tmp);
- }
- if(Kruskal()) printf("%d\n",ans);
- else printf("?\n");
- }
- return ;
- }
- #include<cstdio>
- #define MAXN 105
- #define INF 0x3f3f3f3f
- int map[MAXN][MAXN];
- int dist[MAXN];
- int vis[MAXN];
- int n,m,a,b,x,ans,tot;
- void init()
- {
- for(int i=;i<=n;i++)
- {
- for(int j=;j<=n;j++)
- {
- if(i==j) map[i][j]=;
- else map[i][j]=INF;
- }
- dist[i]=INF;
- }
- }
- int Prim()
- {
- ans=;
- for(int i=;i<=n;i++)
- {
- if(map[][i]<INF)
- dist[i]=map[][i];
- vis[i]=;
- }
- vis[]=;
- int tmp,u=;
- for(int i=;i<=n;i++)
- {
- tmp=INF;
- for(int j=;j<=n;j++)
- {
- if(!vis[j]&&dist[j]<tmp)
- {
- u=j;
- tmp=dist[j];
- }
- }
- if(vis[u]) return ;
- vis[u]=;
- ans+=tmp;
- for(int j=;j<=n;j++)
- {
- if(!vis[j]&&map[u][j]<dist[j])
- dist[j]=map[u][j];
- }
- }
- return ;
- }
- int main()
- {
- while(scanf("%d%d",&m,&n)!=EOF)
- {
- if(m==) break;
- init();
- for(int i=;i<m;i++)
- {
- scanf("%d%d%d",&a,&b,&x);
- if(map[a][b]>x)
- {
- map[a][b]=x;
- map[b][a]=x;
- }
- }
- if(Prim()) printf("%d\n",ans);
- else printf("?\n");
- }
- return ;
- }
HDOJ 1875 畅通工程再续
http://acm.hdu.edu.cn/showproblem.php?pid=1875
把int换成double就行了,还有用Prim比Kruskal好点 因为每条边都得算
- #include<cstdio>
- #include<cmath>
- #define INF 0x3f3f3f3f
- #define MAXN 105
- int point[MAXN][];//保存点的坐标
- double map[MAXN][MAXN];//map矩阵
- int vis[MAXN];//访问标记数组
- double dist[MAXN];//没有加入到MST的点到MST的最短距离
- int n,flag;
- double ans;
- double calc(int x1,int y1,int x2,int y2)
- {
- return sqrt((double)((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
- }
- int Prim()
- {
- ans=;
- for(int i=;i<n;i++)
- {
- dist[i]=map[][i];
- vis[i]=;
- }
- int u=;
- double temp;
- vis[]=;
- for(int i=;i<n;i++)
- {
- temp=INF;
- flag=;
- for(int j=;j<n;j++)
- {
- if(!vis[j]&&dist[j]<temp)
- {
- u=j;
- temp=dist[j];
- flag=;
- }
- }
- if(!flag) return ;
- vis[u]=;
- ans+=dist[u];
- for(int j=;j<n;j++)
- {
- if(!vis[j]&&map[u][j]<dist[j])
- dist[j]=map[u][j];
- }
- }
- return ;
- }
- void create()
- {
- double tmp;
- for(int i=;i<n;i++)
- {
- for(int j=i+;j<n;j++)
- {
- tmp=calc(point[i][],point[i][],point[j][],point[j][]);
- if(tmp<10.0||tmp>1000.0)
- {
- map[i][j]=INF;
- map[j][i]=INF;
- }else
- {
- map[i][j]=tmp;
- map[j][i]=tmp;
- }
- }
- map[i][i]=0.0;
- }
- }
- int main()
- {
- int T;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d",&n);
- for(int i=;i<n;i++)
- {
- scanf("%d%d",&point[i][],&point[i][]);
- }
- create();
- if(Prim()) printf("%.1f\n", ans*);
- else puts("oh!");
- }
- }
HDOJ 1879 继续畅通工程
http://acm.hdu.edu.cn/showproblem.php?pid=1879
对于已经建好的路 只需在建图时把边权赋为0 然后用Prim或者Kruskal求一棵MST即可
- #include<cstdio>
- #define MAXN 105
- #define INF 0x3f3f3f3f
- int map[MAXN][MAXN];
- int dist[MAXN];
- int vis[MAXN];
- int n,m,a,b,x,ans,tot,op;
- void init()
- {
- for(int i=;i<=n;i++)
- {
- for(int j=;j<=n;j++)
- {
- if(i==j) map[i][j]=;
- else map[i][j]=INF;
- }
- dist[i]=INF;
- }
- }
- int Prim()
- {
- ans=;
- for(int i=;i<=n;i++)
- {
- if(map[][i]<INF)
- dist[i]=map[][i];
- vis[i]=;
- }
- vis[]=;
- int tmp,u=;
- for(int i=;i<=n;i++)
- {
- tmp=INF;
- for(int j=;j<=n;j++)
- {
- if(!vis[j]&&dist[j]<tmp)
- {
- u=j;
- tmp=dist[j];
- }
- }
- if(vis[u]) return ;
- vis[u]=;
- ans+=tmp;
- for(int j=;j<=n;j++)
- {
- if(!vis[j]&&map[u][j]<dist[j])
- dist[j]=map[u][j];
- }
- }
- return ;
- }
- int main()
- {
- while(scanf("%d",&n)!=EOF)
- {
- if(n==) break;
- init();
- for(int i=;i<n*(n-)/;i++)
- {
- scanf("%d%d%d%d",&a,&b,&x,&op);
- if(op==) x=;//已经建好的路 权值赋为0 然后求一棵MST即可
- if(map[a][b]>x)
- {
- map[a][b]=x;
- map[b][a]=x;
- }
- }
- if(Prim()) printf("%d\n",ans);
- else printf("?\n");
- }
- return ;
- }
ZOJ 3204 Connect them
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3367
这题要求按最小的字典序输出最小生成树中的边的各个顶点...
在用Kruskal的时候,在边入优先队列的时候就得按照权值,x坐标,y坐标排序,
否则取得的最小生成树可能就是不符合题意的,这样在输出时候按照字典序输出了也是WA
- #include<cstdio>
- #include<queue>
- #include<algorithm>
- #define INf 0x3f3f3f3f
- #define MAXN 105
- using namespace std;
- // int map[MAXN][MAXN];
- int father[MAXN];
- int n,tot,a;
- int find(int x)
- {
- return father[x]==x?x:father[x]=find(father[x]);
- }
- int merge(int a,int b)
- {
- int fa=find(a);
- int fb=find(b);
- if(fa!=fb)
- {
- father[fa]=fb;
- return ;
- }
- return ;
- }
- struct line
- {
- int x,y,w;
- friend bool operator<(line a,line b)//在找边时候同样权值的边也得按照字典序来取 开始没写后两行判断 WA数次...
- {
- if(a.w!=b.w)return a.w>b.w;
- else if(a.x!=b.x)return a.x>b.x;
- else return a.y>b.y;
- }
- };
- line print[];
- line tmp;
- priority_queue<line> q;
- void Kruskal()
- {
- tot=;
- while(!q.empty())
- {
- tmp=q.top();
- q.pop();
- if(merge(tmp.x,tmp.y))
- {
- print[tot++]=tmp;
- }
- }
- }
- void init()
- {
- for(int i=;i<=n;i++)
- {
- father[i]=i;
- }
- while(!q.empty()) q.pop();
- }
- bool cmp(line a,line b)
- {
- if(a.x==b.x) return a.y<b.y;
- else return a.x<b.x;
- }
- int main()
- {
- int T;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d",&n);
- init();
- for(int i=;i<=n;i++)
- {
- for(int j=;j<=n;j++)
- {
- scanf("%d",&a);
- if(a!=&&i<j)
- {
- tmp.x=i;
- tmp.y=j;
- tmp.w=a;
- q.push(tmp);
- }
- }
- }
- Kruskal();
- if(tot==n-)
- {
- sort(print,print+n-,cmp);
- for(int i=;i<n-;i++)
- {
- printf("%d %d ", print[i].x,print[i].y);
- }
- printf("%d %d\n", print[n-].x,print[n-].y);
- }else
- {
- printf("-1\n");
- }
- }
- }
POJ 2349 Arctic Network
http://poj.org/problem?id=2349
这题有点难度,关键是分析出问题的本质...
要求任意两个不用卫星连通的城市之间的距离不超过d,则d越小,这个图被分成的连通块数量越多,卫星的数量就是连通块的数量-1
所以要求的d是一个恰好使这个图分成k+1个连通分量的一个最小值...
然后有这么一个定理:一个值能把这个图分成k个连通分量,则肯定能把这个图的最小生成树分成k个连通分量...
亦即 求最小生成树中的第K长边,可以想到Kruskal用的就是每次加入一条最小边的贪心法形成一棵MST
最小生成树共有n-1条边,第k长边,也就是Kruskal加入的第(n-k)条边,问题得解...具体见代码
- #include<cstdio>
- #include<queue>
- #include<cmath>
- #define MAXN 550
- // #define INF 0x3f3f3f3f
- using namespace std;
- int k,n,cnt;
- int father[MAXN];
- int find(int x)
- {
- return father[x]==x?x:father[x]=find(father[x]);
- }
- int merge(int a,int b)
- {
- int fa=find(a);
- int fb=find(b);
- if(fa!=fb)
- {
- father[fa]=fb;
- return ;
- }
- return ;
- }
- struct edge
- {
- int x,y;
- double w;
- friend bool operator<(edge a,edge b)
- {
- return a.w>b.w;
- }
- };
- edge tmp;
- priority_queue<edge> q;
- int point[MAXN][];
- double clac(int x1,int y1,int x2,int y2)
- {
- return sqrt((double)((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
- }
- void add()
- {
- for(int i=;i<n;i++)
- {
- for(int j=i+;j<n;j++)
- {
- tmp.x=i;
- tmp.y=j;
- tmp.w=clac(point[i][],point[i][],point[j][],point[j][]);
- q.push(tmp);
- }
- }
- }
- double Kruskal()
- {
- for(int i=;i<n;i++)
- father[i]=i;
- cnt=;
- while(!q.empty())
- {
- tmp=q.top();
- q.pop();
- if(merge(tmp.x,tmp.y))
- {
- cnt++;
- if(cnt==n-k) return tmp.w;//做了一点优化,找到第k长边就返回,快了大概200ms
- }
- }
- return ;
- }
- int main()
- {
- int T;
- scanf("%d",&T);
- while(T--)
- {
- while(!q.empty()) q.pop();
- scanf("%d%d",&k,&n);
- for(int i=;i<n;i++)
- {
- scanf("%d%d",&point[i][],&point[i][]);
- }
- add();
- printf("%.2f\n",Kruskal());
- }
- return ;
- }
持续更新中...
MST最小生成树的更多相关文章
- [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)
1937: [Shoi2004]Mst 最小生成树 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 802 Solved: 344[Submit][Sta ...
- 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)
[BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...
- [poj1679]The Unique MST(最小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28207 Accepted: 10073 ...
- UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)
题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...
- MST最小生成树及克鲁斯卡尔(Kruskal)算法
最小生成树MST,英文名如何拼写已忘,应该是min spaning tree吧.假设一个无向连通图有n个节点,那么它的生成树就是包括这n个节点的无环连通图,无环即形成树.最小生成树是对边上权重的考虑, ...
- MST最小生成树及Prim普鲁姆算法
MST在前面学习了Kruskal算法,还有一种算法叫做Prim的.这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图.其时间复杂度为O(n^2),其时间复杂度与边的数目无关:而 ...
- 【KM】BZOJ1937 [Shoi2004]Mst 最小生成树
这道题拖了好久因为懒,结果1A了,惊讶∑( 口 || [题目大意] 给定一张n个顶点m条边的有权无向图.现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值.求最小代价之和. ...
- Prim求MST最小生成树
最小生成树即在一个图中用最小权值的边将所有点连接起来.prim算法求MST其实它的主要思路和dijkstra的松弛操作十分相似 prim算法思想:在图中随便找一个点开始这里我们假定起点为“1”,以点1 ...
- 【BZOJ2238】Mst 最小生成树+LCA+堆
[BZOJ2238]Mst Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的 ...
随机推荐
- supervisor "INFO spawnerr: unknown error making dispatchers for xxx" 错误
查看 supervisor 的配置中,是否有受限的文件路径,如果有,则需要修改对应文件的权限
- GNU C ------ __attribute__
attribute是GNU C特色之一,attribute可以设置函数属性(Function Attribute ).变量属性(Variable Attribute )和类型属性(Type Attri ...
- OneProxy实现mysql读写分离
OneProxy for MySQL可以复用不同应用到后端数据库的连接,有效降低数据库的并发连接数:可以即时踢除不可用的节点,将应用请求转发到其他可用节点,保证业务服务的稳定性. 可透明地将查询语句分 ...
- Python【第三方模块&标准模块】
模块: 模块其实就是一个python文件 1.标准模块.标准包 #python自带的这些模块,直接import就能用的 import string,random,datetime,os,json 2. ...
- Hadoop生态圈-Sqoop部署以及基本使用方法
Hadoop生态圈-Sqoop部署以及基本使用方法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Sqoop(发音:skup)是一款开源的工具,主要用于在Hadoop(Hive)与 ...
- SQL优化:
今日给人查找数据,时间关系,写个比较粗暴的SQL语句: #2s587ms#直接将所有表关联,比较粗暴 select go.businessId,dd.dict_namefrom fn_xte.gt ...
- jsp中jsp:forward 与 redirect区别
部分转载:http://hi.baidu.com/168zlf/item/2f4b2ad4351b881c20e2500c 在网上看到一些帖子,总结了一些区别,可以从以下几个方面来看: 1.从地址栏显 ...
- kibana多台服务部署
nohup /usr/share/kibana/bin/kibana -c /etc/kibana/kibana5602.yml & cp kibana.yml kibana5602.yml ...
- 调用weka模拟实现 “主动学习“ 算法
主动学习: 主动学习的过程:需要分类器与标记专家进行交互.一个典型的过程: (1)基于少量已标记样本构建模型 (2)从未标记样本中选出信息量最大的样本,交给专家进行标记 (3)将这些样本与之前样本进行 ...
- 【转】(总结)Nginx配置文件nginx.conf中文详解
本文转载自:http://www.ha97.com/5194.html 定义Nginx运行的用户和用户组 user www www; nginx进程数,建议设置为等于CPU总核心数 worker_pr ...