例题:最短网络 图论算法之最小生成树 prim//kruskal 学习笔记

图论算法之最小生成树  prim//kruskal

        最小生成树简单的说就是在一个图里选取一些边,使这些边以及它们所连接的结点组成一棵树(两两结点之间可以到达),并且使选取的边的边权最小。
        它的成立条件是图是连通的。并且选取的边数为n-1。(有n个结点,n-1条边,只能为一棵树,没有别的可能)
        主要有两个算法:prim和kruskal

prim

【思路】

        prim算法写起来和dijkstra很像,因为他们的大体思路是一样的。s[i]表示与i相连的所有边的最小值(条件是这条边的另一端点已经是之前扩展过的)。每一次找到s值最小的点,用它去扩展和他相连的所有的边的另一结点,经过n-1此操作,就可以完成对所有点和边的扩展。

【代码】

#include
#include
#include
using namespace std;
int n,i,j,Min,minj,tot;
int a[105][105],s[105];
bool b[105];

int main()
{
	scanf("%d",&n);
	for (i=1;i<=n;++i)
	  for (j=1;j<=n;++j)
	    scanf("%d",&a[i][j]);
	for (i=1;i<=n;++i)
	  s[i]=0x7777777;
	s[1]=0;
	for (i=1;i<=n-1;++i)
	{
		Min=0x7777777;
		for (j=1;j<=n;++j)
		  if (!b[j]&&s[j]

【求出最小生成树中的所有边】

也不是很难想,只要再加一个前驱就行了,最后递归输出;

【代码】

#include
#include
#include
using namespace std;
int n,i,j,Min,minj,tot;
int a[105][105],s[105],pre[105];
bool b[105];

void print(int x)
{
	if (pre[x]==0)
	{
		printf("%d\n",x);
		return;
	}
	print(pre[x]);
	printf("%d\n",x);
	return;
}

int main()
{
	scanf("%d",&n);
	for (i=1;i<=n;++i)
	  for (j=1;j<=n;++j)
	    scanf("%d",&a[i][j]);
	for (i=1;i<=n;++i)
	  s[i]=0x7777777;
	s[1]=0;
	for (i=1;i<=n-1;++i)
	{
		Min=0x7777777;
		for (j=1;j<=n;++j)
		  if (!b[j]&&s[j]

例:最优布线问题

【问题描述】
  学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们间有数据线连接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。
    当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。
  现在由你负责连接这些计算机,任务是使任意两台计算机都连通(不管是直接的或间接的)。
【输入格式】
  输入文件wire.in,第一行为整数n(2<=n<=100),表示计算机的数目。此后的n行,每行n个整数。第x+1行y列的整数表示直接连接第x台计算机和第y台计算机的费用。
【输出格式】
  输出文件wire.out,一个整数,表示最小的连接费用。
【输入样例】
  3
  0 1 2
  1 0 1
  2 1 0
【输出样例】
    2   (注:表示连接1和2,2和3,费用为2)

【解题思路】
prim裸题,直接用上面给的标算都能过。。在此就不粘代码了->_->

kruskal

【算法描述】

需要用到并查集,具体过程如下:
1.初始化并查集。father[x]=x。
2.tot=0
3.将所有边用快排从小到大排序。
4.计数器 k=0;
5.for (i=1; i<=M; i++)      //循环所有已从小到大排序的边
  if  这是一条u,v不属于同一集合的边(u,v)(因为已经排序,所以必为最小),
    begin
     ①合并u,v所在的集合,相当于把边(u,v)加入最小生成树。
     ②tot=tot+W(u,v)
      ③k++
      ④如果k=n-1,说明最小生成树已经生成,则break;
    end;
6. 结束,tot即为最小生成树的总权值之和。

【代码】

#include
#include
#include
#include
using namespace std;
struct hp{
	int x,y,s;
}a[10005];
int n,i,j,dis,num,tot,k;
int father[10005];

int cmp(hp a,hp b)
{
	return a.s

【记录路径】

其实并没有什么好说的,加一个bool或者别的什么记录一下,最后按顺序输出即可;

例:最短网络

【问题描述】
  农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。每两个农场间的距离不会超过100000。
【输入格式】
第一行:
农场的个数,N(3<=N<=100)。
第二行..结尾
后来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们限制在80个字符,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为不会有线路从第i个农场到它本身。
【输出格式】
    只有一个输出,其中包含连接到每个农场的光纤的最小长度。
【输入样例】agrinet.in
    4
    0  4  9  21
    4  0  8  17
    9  8  0  16
    21 17 16  0
【输出样例】agrinet.out
28

【解题思路】
kruskal裸题。。。依然是用标算就能过,,,我闲的没事粘上来。。。<-_<-

你可能感兴趣的:(题解,并查集,图论算法,学习笔记)