HDU1102--最小生成树
Constructing Roads
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9149 Accepted Submission(s): 3383
We
know that there are already some roads between some villages and your
job is the build some roads such that all the villages are connect and
the length of all the roads built is minimum.
<= 100), which is the number of villages. Then come N lines, the
i-th of which contains N integers, and the j-th of these N integers is
the distance (the distance should be an integer within [1, 1000])
between village i and village j.
Then there is an integer Q (0 <=
Q <= N * (N + 1) / 2). Then come Q lines, each line contains two
integers a and b (1 <= a < b <= N), which means the road
between village a and village b has been built.
which is the length of all the roads to be built such that all the
villages are connected, and this value is minimum.
Prim算法
1.概览
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。
2.算法简单描述
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来描述所得到的最小生成树。
下面对算法的图例描述
图例 | 说明 | 不可选 | 可选 | 已选(Vnew) |
---|---|---|---|---|
此为原始的加权连通图。每条边一侧的数字代表其权值。 | - | - | - | |
顶点D被任意选为起始点。顶点A、B、E和F通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。 | C, G | A, B, E, F | D | |
下一个顶点为距离D或A最近的顶点。B距D为9,距A为7,E为15,F为6。因此,F距D或A最近,因此将顶点F与相应边DF以高亮表示。 | C, G | B, E, F | A, D | |
算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。 | C | B, E, G | A, D, F | |
在当前情况下,可以在C、E与G间进行选择。C距B为8,E距B为7,G距F为11。E最近,因此将顶点E与相应边BE高亮表示。 | 无 | C, E, G | A, D, F, B | |
这里,可供选择的顶点只有C和G。C距E为5,G距E为9,故选取C,并与边EC一同高亮表示。 | 无 | C, G | A, D, F, B, E | |
顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG。 | 无 | G | A, D, F, B, E, C | |
现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。 | 无 | 无 | A, D, F, B, E, C, G |
3.简单证明prim算法
反证法:假设prim生成的不是最小生成树
1).设prim生成的树为G0
2).假设存在Gmin使得cost(Gmin)<cost(G0) 则在Gmin中存在<u,v>不属于G0
3).将<u,v>加入G0中可得一个环,且<u,v>不是该环的最长边(这是因为<u,v>∈Gmin)
4).这与prim每次生成最短边矛盾
5).故假设不成立,命题得证.
4.PRIM代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int INF=;
const int MAXN=; int n,m;
int map[MAXN][MAXN];
int dis[MAXN];
int visit[MAXN]; int prim()
{
for(int i=; i<=n; i++)
dis[i]=INF; dis[]=; //起点为顶点1
for(int j=; j<=n; j++)
{
int t=INF,pos; //临时变量:最短路径距离t,和该顶点pos
for(int i=; i<=n; i++) //查找最短路径'点'
{
if(!visit[i]&&t>dis[i])
{
t=dis[i];
pos=i;
}
}
visit[pos]=; //最短路径点标记为已经访问
for(int i=; i<=n; i++) //更新最短路径点
{
//如果,顶点i未被访问过
//且图中新加入的pos点到i点的距离短于原来图到i点的距离
//且pos到i的点有连通(即不为无穷大),则将i点到图的距离更新.
if(!visit[i]&&dis[i]>map[pos][i]&&map[pos][i]!=INF)
{
dis[i]=map[pos][i];
}
}
}
int temp=;
for(int k=; k<=n; k++)
{
temp+=dis[k];
}
return temp;
} int main()
{
int a,b;
while(cin>>n)
{
memset(map,0x3f,sizeof(map));
memset(visit,,sizeof(visit));
for(int i=; i<=n; i++)
{
for(int j=; j<=n; j++)
{
cin>>map[i][j];
}
}
cin>>m;
while(m--)
{
cin>>a>>b;
map[a][b]=;
map[b][a]=;
}
int ans=prim();
cout<<ans<<endl;
}
return ;
}
Kruskal算法
1.概览
Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪婪算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
2.算法简单描述
1).记Graph中有v个顶点,e个边
2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
3).将原图Graph中所有e个边按权值从小到大排序
4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中
if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中
添加这条边到图Graphnew中
图例描述:
首先第一步,我们有一张图Graph,有若干点和边
将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择,排序完成后,我们率先选择了边AD。这样我们的图就变成了右图
在剩下的变中寻找。我们找到了CE。这里边的权重也是5
依次类推我们找到了6,7,7,即DF,AB,BE。
下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。
3.简单证明Kruskal算法
对图的顶点数n做归纳,证明Kruskal算法对任意n阶图适用。
归纳基础:
n=1,显然能够找到最小生成树。
归纳过程:
假设Kruskal算法对n≤k阶图适用,那么,在k+1阶图G中,我们把最短边的两个端点a和b做一个合并操作,即把u与v合为一个点v',把原 来接在u和v的边都接到v'上去,这样就能够得到一个k阶图G'(u,v的合并是k+1少一条边),G'最小生成树T'可以用Kruskal算法得到。
我们证明T'+{<u,v>}是G的最小生成树。
用反证法,如果T'+{<u,v>}不是最小生成树,最小生成树是T,即W(T)<W(T'+{<u,v>})。显然T应该包含<u,v>,否则,可以用<u,v>加入到T中,形成一个环,删除环上原有的任意一条边,形成一棵更小权值的生成树。而T-{<u,v>},是G'的生成树。所以W(T-{<u,v>})<=W(T'),也就是W(T)<=W(T')+W(<u,v>)=W(T'+{<u,v>}),产生了矛盾。于是假设不成立,T'+{<u,v>}是G的最小生成树,Kruskal算法对k+1阶图也适用。
由数学归纳法,Kruskal算法得证。
4.Kruskal代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int fa[];
int n,m;
int cc;
struct edge
{
int u,v,w;
void set(int x,int y,int s)
{
u=x;
v=y;
w=s;
} }e[];
int find(int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
void kruskal()
{
int ans=;cc=n;
sort(e,e+n*n,cmp);
for(int i=; i<n*n; i++)
{
int x=find(e[i].u);
int y=find(e[i].v);
if(x!=y)
{
fa[x]=y;
ans+=e[i].w;
cc--;
}
}
if(cc==)
printf("%d\n",ans);
} void init()
{
for(int i=; i<n; i++)
fa[i]=i; }
int main()
{
while(cin>>n)
{
init();
int cnt=;int d[][];
for(int i=; i<n; i++)
for(int j=; j<n; j++)
scanf("%d",&d[i][j]);
int Q;
cin>>Q;
int a,b;
for(int i=; i<Q; i++)
{
scanf("%d%d",&a,&b);
d[a-][b-]=;
}
for(int i=; i<n; i++)
for(int j=; j<n; j++)
{ e[cnt].set(i,j,d[i][j]); cnt++;
}
kruskal(); }
return ;
}
本小白觉得的 这个 跟 最短路有些像呢
HDU1102--最小生成树的更多相关文章
- HDU1102 最小生成树prim算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 题意:给出任意两个城市之间建一条路的时间,给出哪些城市之间已经建好,问最少还要多少时间使所有的城 ...
- HDU1102(最小生成树Kruskal算法)
Constructing Roads Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- HDU1102 Constructing Roads —— 最小生成树
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 题解: 纯最小生成树,只是有些边已经确定了要加入生成树中,特殊处理一下这些边就可以了. krus ...
- HDU1102(最小生成树Kruskal)
开学第三周.........真快尼 没有计划的生活真的会误入歧途anytime 表示不开心不开心不开心 每天都觉得自己的生活很忙 又觉得想做的事又没有完成 这学期本来计划重点好好学算法,打码码,臭臭美 ...
- hdu1102 Constructing Roads (简单最小生成树Prim算法)
Problem Description There are N villages, which are numbered from 1 to N, and you should build some ...
- POJ2421 & HDU1102 Constructing Roads(最小生成树)
嘎唔!~又一次POJ过了HDU错了...不禁让我想起前两天的的Is it a tree? orz..这次竟然错在HDU一定要是多组数据输入输出!(无力吐槽TT)..题目很简单,炒鸡水! 题意: 告 ...
- hdu1102 Constructing Roads 基础最小生成树
//克鲁斯卡尔(最小生成树) #include<cstdio> #include<iostream> #include<algorithm> using names ...
- hdu1102(最小生成树水题)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> us ...
- POJ 2485 Highways && HDU1102(20/200)
题目链接:Highways 没看题,看了输入输出.就有种似曾相识的感觉,果然和HDU1102 题相似度99%,可是也遇到一坑 cin输入居然TLE,cin的缓存不至于这么狠吧,题目非常水.矩阵已经告诉 ...
- 最小生成树(Kruskal算法-边集数组)
以此图为例: package com.datastruct; import java.util.Scanner; public class TestKruskal { private static c ...
随机推荐
- DNS(一)之禁用权威域名服务器递归解析
DNS dns是互联网中最核心的带层级的分布式系统,负责把域名解析成ip,把IP解析出域名,以及宣告邮件路由信息等等,使得使用域名访问网站,收发邮件成了可能. bind(berkeley Intern ...
- UVALive 3989Ladies' Choice(稳定婚姻问题)
题目链接 题意:n个男生和女生,先是n行n个数,表示每一个女生对男生的好感值排序,然后是n行n列式每一个男生的好感值排序,输出N行,即每个女生在最好情况下的男生的编号 分析:如果是求女生的最好情况下, ...
- JAVA 自定义状态码
返回信息类(ResponseInfo): public class ResponseInfo { public static final String Status = "status&qu ...
- 爬虫5 html下载器 html_downloader.py
#coding:utf8 import urllib2 __author__ = 'wang' class HtmlDownloader(object): def download(self, url ...
- Visual Studio 2012优化
http://msdn.microsoft.com/en-us/library/ms182372.aspx
- ecshop 团购点击价格变动
前提:价格阶梯只能设置一级 需要用到: jquery,transport.js(transport_jquery.js),Ajax.call html页面 js代码,还需要插入jquery,trans ...
- yourphp的edit,updata,dele
参考文件Yourphp\Lib\Action\User\PostAction.class.php public function add() { $form=new Form(); $form-> ...
- PHP页面跳转
PHP页面跳转一.header()函数 header()函数是PHP中进行页面跳转的一种十分简单的方法.header()函数的主要功能是将HTTP协议标头(header)输出到浏览器. header( ...
- Redis学习——SDS字符串源码分析
0. 前言 这里对Redis底层字符串的实现分析,但是看完其实现还没有完整的一个概念,即不太清楚作者为什么要这样子设计,只能窥知一点,需要看完redis如何使用再回头来体会,有不足之处还望告知. 涉及 ...
- webapi输入验证过滤器ValidationActionFilter
public class validationActionFilter:ActionFilterAttribute { public override void OnActionExecuting(S ...