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个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的 ...
随机推荐
- 题解【bzoj1503 [NOI2004]郁闷的出纳员】
Description 给出一个下限 \(m\) ,要求维护以下操作 插入一个数(如果小于下限就不加) 给每个数加上一个数 给每个数减去一个数,并且删除掉 \(< m\) 的所有数 求目前第 \ ...
- [Linux]-Linux常用命令之文件解压
不压缩方式压缩的文件需要不同的命令来解压缩,下面是Linux的各种文件解压命令. 对于.tar结尾的文件: tar -xf 对于.gz结尾的文件 : gzip -d all.gz gunzip all ...
- Java基础-IO流对象之File类
Java基础-IO流对象之File类 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.IO技术概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下 ...
- eclipse 无法解析导入 javax.servlet 的解决方法
出现上述问题的原因是你的Eclipse项目没有导入JSP运行所需要的Tomcat类库,主要是servlet-api.jar文件(或者servlet.jar),tomcat容器里面有这文件,在以下位置: ...
- Matlab debug
输入彩色,imwrite保存黑白图片,imwrite的维度错误. 程序如下,正常图像,少了一个维度imwrite,把图片展开,是一个二维的灰色图像(R=G=B),.如果限定了第二维,也是一个灰色图像. ...
- 你知道吗?什么是 Responsive JavaScript ?
Responsive Javascript 是什么? 简单来说就是可以根据浏览器的状态做出响应.响应包括对视窗大小的反应,根据你设备是否支持触摸事件或地理定位功能来决定是否显示特定内容,不一而足. 什 ...
- 20155227 2016-2017-2 《Java程序设计》第七周学习总结
20155227 2016-2017-2 <Java程序设计>第七周学习总结 教材学习内容总结 认识时间与日期 时间的度量 世界时:在1972年引入UTC之前,GMT与UT是相同的. 国际 ...
- phpcms数据结构
v9_admin 管理员表 v9_admin_panel 快捷面板 v9_admin_role 角色表 v9_admin_role_priv 管理员权限表 v9_announce 公告表 v9_att ...
- NYOJ 116 士兵杀敌(二) (树状数组)
题目链接 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的.小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧.南将军的某次询问之后 ...
- 【CC2530强化实训01】普通延时函数实现按键的长按与短按
[CC2530强化实训01]普通延时函数实现按键的长按与短按 [题目要求] 用一个按键实现长按与短按的功能已经是很多嵌入式产品的常用手法.使用定时器的间隔定时来进行按键按下的时间是通用的做法, ...