首先,贴上一个很好的讲解贴:

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最小生成树的更多相关文章

  1. [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)

    1937: [Shoi2004]Mst 最小生成树 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 802  Solved: 344[Submit][Sta ...

  2. 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)

    [BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...

  3. [poj1679]The Unique MST(最小生成树)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28207   Accepted: 10073 ...

  4. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

  5. MST最小生成树及克鲁斯卡尔(Kruskal)算法

    最小生成树MST,英文名如何拼写已忘,应该是min spaning tree吧.假设一个无向连通图有n个节点,那么它的生成树就是包括这n个节点的无环连通图,无环即形成树.最小生成树是对边上权重的考虑, ...

  6. MST最小生成树及Prim普鲁姆算法

    MST在前面学习了Kruskal算法,还有一种算法叫做Prim的.这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图.其时间复杂度为O(n^2),其时间复杂度与边的数目无关:而 ...

  7. 【KM】BZOJ1937 [Shoi2004]Mst 最小生成树

    这道题拖了好久因为懒,结果1A了,惊讶∑( 口 || [题目大意] 给定一张n个顶点m条边的有权无向图.现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值.求最小代价之和. ...

  8. Prim求MST最小生成树

    最小生成树即在一个图中用最小权值的边将所有点连接起来.prim算法求MST其实它的主要思路和dijkstra的松弛操作十分相似 prim算法思想:在图中随便找一个点开始这里我们假定起点为“1”,以点1 ...

  9. 【BZOJ2238】Mst 最小生成树+LCA+堆

    [BZOJ2238]Mst Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的 ...

随机推荐

  1. web项目中classPath指的是哪里?

    classpath可以是SRC下面的路径 但是项目最终编译会到WEB-INF下面,所以有时候WEB-INF下面的classes也可以放配置文件,也可以读取到. 因为最终src都会放到WEB-INF下面 ...

  2. Dockerfile 部署 nodejs

    1.编写.dockerignore 构建镜像时,并不需要node_modules目录等内容,可以使用.dockerignore忽略一些文件 # .dockerignore Dockerfile nod ...

  3. U45490 还没想好名字的题Ⅱ

    这一题的环状板 Solution 暴力断环为链, 枚举起点跑 \(n\) 遍 \(DP\), 取最小值即可 Code #include<iostream> #include<cstd ...

  4. Java基础-IO流对象之字节流(Stream)

    Java基础-IO流对象之字节流(Stream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在前面我分享的笔记中,我们一直都是在操作文件或者文件夹,并没有给文件中写任何数据.现 ...

  5. IDEA Mybatis plugin插件破解

    破解文件: 链接:https://pan.baidu.com/s/1J7asfLc5I0RBcoYX3_yNvQ 提取码:kjxv 使用方法: C:\Users\{你的用户名}\.IntelliJId ...

  6. Redis配置及使用

    1.参考资料 在线命令说明: http://doc.redisfans.com/ redis安装列表: https://github.com/rgl/redis/downloads Redis工具使用 ...

  7. [LeetCode] 398. Random Pick Index ☆☆☆

    Given an array of integers with possible duplicates, randomly output the index of a given target num ...

  8. 洛谷 p2066 机器分配(资源型)

    机器分配 https://www.luogu.org/problem/show?pid=2066 题目描述 总公司拥有高效设备M台,准备分给下属的N个分公司.各分公司若获得这些设备,可以为国家提供一定 ...

  9. linux scp上传文件到其他机器上

    scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器 ...

  10. eclipse配置hadoop插件

    1. 版本信息   eclipse windows 64 bit hadoop 2.5.2 64 bit hadoop eclipse-plug 2.5.2   2. 下载hadoop-2.5.2.t ...