最小生成树

有关生成树的几个概念:

连通图:在无向图中,若任意两个顶点都有路径相通,则称该无向图为连通图。

强连通图:在有向图中,若任意两个顶点都有路径相通,则称该有向图为强连通图。

连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权;权代表着连接连个顶点的代价,称这种连通图叫做连通网。

生成树:一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。

最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树(即权重和最小),称为最小生成树。(最小权重和生成树的简称)

最小生成树可以用prim(普里姆)算法或Kruskcal(克鲁斯卡尔)算法求出。

特别地,瓶颈生成树:在无向图G中的瓶颈生成树,它的最大边权值是G中所有生成树的最大边权值最小的那个。

无向图的最小生成树一定是瓶颈生成树,但瓶颈生成树不一定是最小生成树。(最小瓶颈生成树==最小生成树)

prim(普里姆)算法:用类似Dijkstra最短路径算法,首先用数组dis来记录生成树到各个顶点的距离,也就是说记录现在的最短距离,不是Dijkstra中每个顶点到1号顶点的最短距离,而是每个顶点到任意一个“树顶点”(已被选入生成树的顶点)的最短距离即dis[k]>e[j][k]则更新dis[k]=e[j][k];不需要加dis[j]了,我们的目的并不是非得靠近1号顶点,只需靠近生成树任意一个顶点就可以。

Kruskcal(克鲁斯卡尔)算法:通过从小到大排序边权值,结合并查集算法,通过不断连通顶点找到最小权值和。

特殊地,对于数据量较大的题,以下方法会超时

int getf(int x){
     if(f[x]==x) return x;
     else return getf(f[x]);///递归太多
}

改进:

int getf(int x){
     if(f[x]!=x)  f[x]=getf(f[x]);
     return f[x];///一步到位,找到才退出
}

 如牛客网题:

    胡队长带领HA实验的战士们玩真人CS,真人CS的地图由一些据点组成,现在胡队长已经占领了n个据点,为了方便,将他们编号为1-n,为了隐蔽,胡队长命令战士们在每个据点出挖一个坑,让战士们躲在坑里。由于需要在任意两个点之间传递信息,两个坑之间必须挖出至少一条通路,而挖沟是一件很麻烦的差事,所以胡队长希望挖出数量尽可能少的沟,使得任意两个据点之间有至少一条通路,顺便,尽可能的∑d[i][j]使最小(其中d[i][j]为据点i到j的距离)。

输入描述:

第一行有2个正整数n,m,m表示可供挖的沟数。
接下来m行,每行3个数a,b,v,每行描述一条可供挖的沟,该沟可以使a与b连通,长度为v。

输出描述:

输出一行,一个正整数,表示要使得任意两个据点之间有一条通路,至少需要挖长的沟。(数据保证有解)

示例1

输入

复制

2 2
1 2 1
1 2 3

输出

复制

1

示例2

输入

复制

3 3
1 2 3
2 3 4
1 3 5

输出

复制

7

备注:

对于100%的测试数据:
1 ≤ n ≤ 100000
1 ≤ m ≤ 500000
1 ≤ v ≤ 10000
#include 
#include 
using namespace std;
///#define MAXN 100010
struct Edge{
    int u,v,w;
}e[500010];
int f[100010];
bool cmp(Edge a,Edge b){
    return a.w

  

最小生成树(MST)之Kruskcal

Description

给出一个无向图,求该图的最小生成树。

Input

多测试用例。

第一行:两个正整数 N 和 E ( 0 < N < 10000, N < E < 40000 ),分别表示该图的顶点个数、边的总数。顶点编号从 0~N-1

接下来E行,每行是3个整数:u v w,表示 顶点u 与 顶点v 之间有一条权值为w的边。 0 ≤ u ,v < N ,   0 < w < 20

Output

每个测试用例:

如果该图不连通,输出一行: unconnected graph

否则输出n行:第1行是该生成树的边权之和,第2~n行以 u v w 的形式输出生成树的各条边,其中u和v表示这条边的两个顶点,w表示这条边的权重。生成树的边的输出次序不限,只要求不重复、不遗漏。  如:3 7 2 跟  7 3 2 是同一条边。

Sample Input

9 14
0 2 4
0 1 8
2 1 11
2 3 8
1 4 7
1 5 1
4 3 2
5 4 6
5 7 2
7 3 4
6 3 7
7 6 14
6 8 9
7 8 10

Sample Output

37
2 0 4
5 1 1
3 2 8
3 4 2
5 7 2
3 7 4
3 6 7
8 6 9

Hint

样例的图如下:

由于生成树的不唯一性,所以下面的生成树同样正确:

37
2 0 4
5 1 1
0 1 8
3 4 2
5 7 2
3 7 4
3 6 7
8 6 9

此题用Kruskcal(克鲁斯卡尔)算法,由于顶点数过大,二维数组会直接爆了。而且此法不能用快排会超时的。

#include 
#include 
using namespace std;
int f[10010];
struct edge{
   int u;
   int v;
   int w;
}e[40010],t,a[40010];
bool cmp(const struct edge &a,const struct edge &b){
	return a.w=e[L].w&&i

最小生成树(MST)之Prim

Description

给出一个无向网,求该无向网的最小生成树。各条边的权重不超过100000。

本题与下一题的测试数据是一样的,本题请用Prim算法来做,以便与下一题做比较。

Input

输入的第一行是一个整数N,表示该网的顶点个数。 3 ≤ N ≤ 100

接下来是N行,每行N个整数,表示每个顶点到其余顶点的距离。

Output

输出该最小生成树的权重。

Sample Input

4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0

Sample Output

28

此题不像其他题直接给出顶点,边权,而是用矩阵来表示,但是方法也是一样。

#include 
#include 
#define inf 0x3f3f3f3f
using namespace std;
int dis[110],e[110][100];
bool vis[110];
int main()
{
   int coun=0,sum=0;
   int n,x,minx;
   while(~scanf("%d",&n))
   {
       for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
             scanf("%d",&e[i][j]);
       for(int i=1;i<=n;i++)
         dis[i]=e[1][i];
       vis[1]=1;
       coun++;
       while(coune[x][k])
                 dis[k]=e[x][k];
       }
       printf("%d\n",sum);
   }
   return 0;
}

Out of Hay

Description

The cows have run out of hay, a horrible event that must be remedied immediately. Bessie intends to visit the other farms to survey their hay situation. There are N (2 ≤ N ≤ 2,000) farms (numbered 1..N); Bessie starts at Farm 1. She'll traverse some or all of the M (1 ≤ M ≤ 10,000) two-way roads whose length does not exceed 1,000,000,000 that connect the farms. Some farms may be multiply connected with different length roads. All farms are connected one way or another to Farm 1.

Bessie is trying to decide how large a waterskin she will need. She knows that she needs one ounce of water for each unit of length of a road. Since she can get more water at each farm, she's only concerned about the length of the longest road. Of course, she plans her route between farms such that she minimizes the amount of water she must carry.

Help Bessie know the largest amount of water she will ever have to carry: what is the length of longest road she'll have to travel between any two farms, presuming she chooses routes that minimize that number? This means, of course, that she might backtrack over a road in order to minimize the length of the longest road she'll have to traverse.

Input

* Line 1:           Two space-separated integers, N and M.

* Lines 2..1+M:   Line i+1 contains three space-separated integers, AiBi, and Li, describing a road from Ai to Bi of length Li.

Output

* Line 1:   A single integer that is the length of the longest road required to be traversed.

Sample Input

3 3
1 2 23
2 3 1000
1 3 43

Sample Output

43

Hint

OUTPUT DETAILS:

In order to reach farm 2, Bessie travels along a road of length 23. To reach farm 3, Bessie travels along a road of length 43. With capacity 43, she can travel along these roads provided that she refills her tank to maximum capacity before she starts down a road.

此题正是典型的瓶颈生成树。

#include 
#include 
using namespace std;
struct edge{
    int u;
    int v;
    int w;
    }e[10010];
int f[10010];
bool cmp(const edge &a,const edge &b){
    return a.w

Cheering up the Cows

Description

Farmer John has grown so lazy that he no longer wants to continue maintaining the cow paths that currently provide a way to visit each of his N (5 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N). Each and every pasture is home to one cow. FJ plans to remove as many of the P (N-1 ≤ P ≤ 100,000) paths as possible while keeping the pastures connected. You must determine which N-1 paths to keep.

Bidirectional path j connects pastures Sj and Ej (1 ≤ Sj ≤ N; 1 ≤ Ej ≤ NSj ≠ Ej) and requires Lj (0 ≤ Lj ≤ 1,000) time to traverse. No pair of pastures is directly connected by more than one path.

The cows are sad that their transportation system is being reduced. You must visit each cow at least once every day to cheer her up. Every time you visit pasture i (even if you're just traveling through), you must talk to the cow for time Cj(1 ≤ Cj ≤ 1,000).

You will spend each night in the same pasture (which you will choose) until the cows have recovered from their sadness. You will end up talking to the cow in the sleeping pasture at least in the morning when you wake up and in the evening after you have returned to sleep.

Assuming that Farmer John follows your suggestions of which paths to keep and you pick the optimal pasture to sleep in, determine the minimal amount of time it will take you to visit each cow at least once in a day.

Input

* Line 1: Two space-separated integers: N and P

* Lines 2..N+1: Line i+1 contains a single integer: Cj

* Lines N+2..N+P+1: Line N+j+1 contains three space-separated integers: SjEj, and Lj

Output

* Line 1: A single integer, the total time it takes to visit all the cows (including the two visits to the cow in your sleeping-pasture)

Sample Input

5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
4 5 12

Sample Output

176

/*从某根开始走,每走一条边就要消耗两边点权+边的边权*2。最后再加上一个根的点权,问最少花多少代价。*/


#include 
#include 
using namespace std;
int p[10010];
struct edge{
     int u,v,w;
     bool operator < (const edge &a)const{ return wa[v]) f[v]=u;
     else {
        f[u]=v;
        if(a[u]==a[v]) a[v]++;
     }
}
int main(){
     int n,m;
     scanf("%d%d",&n,&m);
            int ans=9999999;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i]);
             if(ans>p[i]) ans=p[i];
             f[i]=i;
        }
        int a,b,c;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            e[i].u=a;
            e[i].v=b;
            e[i].w=p[a]+p[b]+2*c;///两边点权+边的边权*2
        }
        sort(e+1,e+1+m);
        for(int i=1;i<=m;i++){
            if(getf(e[i].u)==getf(e[i].v))   continue;
           ans+=e[i].w;
           mergex(e[i].u,e[i].v);
        }

    printf("%d\n",ans);
     return 0;
}




#include 
#include 
using namespace std;
int p[10010];
struct edge{
     int u,v,w;
     bool operator < (const edge &a)const{ return wp[i]) ans=p[i];
             f[i]=i;
        }
        int a,b,c;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            e[i].u=a;
            e[i].v=b;
            e[i].w=p[a]+p[b]+2*c;///两边点权+边的边权*2
        }
        sort(e+1,e+1+m);
        int cnt=0;
        for(int i=1;i<=m;i++){
            if(mergex(e[i].u,e[i].v))     {
                ans+=e[i].w;
                ++cnt;
           }
           if(cnt==n-1) break;
        }

    printf("%d\n",ans);
     return 0;
}

Slim Span

  • Time Limit: 4000/2000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others)
  • Total Submission(s): 162     Accepted Submission(s): 77

Description

Given an undirected weighted graph G, you should find one of spanning trees specified as follows.

The graph G is an ordered pair (VE), where V is a set of vertices {v1v2, …, vn} and E is a set of undirected edges {e1e2, …, em}. Each edge e ∈ E has its weight w(e).

A spanning tree T is a tree (a connected subgraph without cycles) which connects all the n vertices with n-1 edges. The slimness of a spanning tree T is defined as the difference between the largest weight and the smallest weight among the n-1 edges of T.


Figure 1: A graph G and the weights of the edges

For example, a graph G in Figure 1(a) has four vertices {v1v2v3v4} and five undirected edges {e1e2e3e4e5}. The weights of the edges are w(e1) = 3, w(e2) = 5, w(e3) = 6, w(e4) = 6, w(e5) = 7 as shown in Figure 1(b).


Figure 2: Examples of the spanning trees of G

There are several spanning trees for G. Four of them are depicted in Figure 2(a)~(d). The spanning tree Ta in Figure 2(a) has three edges whose weights are 3, 6 and 7. The largest weight is 7 and the smallest weight is 3 so that the slimness of the tree Ta is 4. The slimnesses of spanning trees TbTc and Td shown in Figure 2(b), (c) and (d) are 3, 2 and 1, respectively. You can easily see the slimness of any other spanning tree is greater than or equal to 1, thus the spanning tree Td in Figure 2(d) is one of the slimmest spanning trees whose slimness is 1.

Your job is to write a program that computes the smallest slimness.

Input

The input consists of multiple datasets, followed by a line containing two zeros separated by a space. Each dataset has the following format.

n m  
a1 b1 w1
   
am bm wm

Every input item in a dataset is a non-negative integer. Items in a line are separated by a space. n is the number of the vertices and m the number of the edges. You can assume 2 ≤ n ≤ 100 and 0 ≤ m ≤ n(n - 1)/2. ak and bk (k = 1, …,m) are positive integers less than or equal to n, which represent the two vertices vak and vbk connected by the k-th edge ekwk is a positive integer less than or equal to 10000, which indicates the weight of ek. You can assume that the graph G = (VE) is simple, that is, there are no self-loops (that connect the same vertex) nor parallel edges (that are two or more edges whose both ends are the same two vertices).

Output

For each dataset, if the graph has spanning trees, the smallest slimness among them should be printed. Otherwise, -1 should be printed. An output should not contain extra characters.

Sample Input

4 5
1 2 3
1 3 5
1 4 6
2 4 6
3 4 7
4 6
1 2 10
1 3 100
1 4 90
2 3 20
2 4 80
3 4 40
2 1
1 2 1
3 0
3 1
1 2 1
3 3
1 2 2
2 3 5
1 3 6
5 10
1 2 110
1 3 120
1 4 130
1 5 120
2 3 110
2 4 120
2 5 130
3 4 120
3 5 110
4 5 120
5 10
1 2 9384
1 3 887
1 4 2778
1 5 6916
2 3 7794
2 4 8336
2 5 5387
3 4 493
3 5 6650
4 5 1422
5 8
1 2 1
2 3 100
3 4 100
4 5 100
1 5 50
2 5 50
3 5 50
4 1 150
0 0

Sample Output

1
20
0
-1
-1
1
0
1686
50

Hint

与“最小生成树”有关:求一棵最大边与最小边差值最小的生成树,可利用kruskal

方法一:二分差值

方法二:枚举最小边

 

#include
#include
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
   int u,v,w;
   bool operator<(const edge&a)const{
        return wtnt) ans=tnt;///更新每个生成树最大边与最小边差值
            }
            if(ans==INF) puts("-1");
            else printf("%d\n",ans);
          }
}

 

你可能感兴趣的:(数据结构)