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

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. 约瑟夫环问题算法(M)

    http://blog.csdn.net/zhuimengzh/article/details/6727221 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出.写出C程序 ...

  2. PhantomJS的替代品--无头浏览器(Headless Chrome)

    在使用PhantomJS时候,出现提示: UserWarning: Selenium support for PhantomJS has been deprecated, please use hea ...

  3. const引用与非const引用

    void print1(int a) { cout<<a<<endl; } void print2(const int& a) { cout<<a<& ...

  4. 内存操作函数memmove,memcpy,memset

    通过字符串的学习,我们知道字符串操作函数的操作对象是字符串,并且它的结束标志是结束符\0,当然这个说的是不 受限制的字符串函数.然而当我们想要将一段内存的数据复制到另一块内存时,我们不能使用字符串操作 ...

  5. 蓝桥杯 方格填数 DFS 全排列 next_permutation用法

    如下的10个格子(参看[图1.jpg]) 填入0~9的数字.要求:连续的两个数字不能相邻.(左右.上下.对角都算相邻) 一共有多少种可能的填数方案? 请填写表示方案数目的整数.注意:你提交的应该是一个 ...

  6. radioButton drawable selector

    1.实现radioButton drawable selector更改图片,在drawable文件夹下,新建selector文件, <selector xmlns:android="h ...

  7. 平铺式窗口管理器 Musca 初体验

    作者: 吴吉庆 Version: 1.0 release: 2009-11-04 update: 2009-11-04 为什么用平铺式窗口管理器? 什么是平铺式窗口管理器(tiling window ...

  8. 地位尴尬的WebForm、ASP.NET核心知识(10)

    WebForm之烦恼 1.winform式的开发方式 WebForm的开发方式中,只需要从工具箱中拖拽一个控件,再从.aspx.cs中写控件的事件逻辑,就好了. 微软为我们做了很多工作,很多东西不需要 ...

  9. zedboard 初使用 -- 工具篇

    <一> 安装ISE和Vivada: <二> 安装USB转UART驱动 <三> 安装USB转JTAG驱动插件 http://blog.sina.com.cn/s/bl ...

  10. Django中HttpRequest和HttpResponse

    请求和响应对象 Django中通过使用请求和响应对象来传递系统的状态. 当请求一个页面的时候,Django就创建一个HttpRequest对象,它包含了关于请求的元数据对象,然后Django加载适当的 ...