MST最小生成树套题训练题解

A - 畅通工程

1、题目描述

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
Sample Output
3
?

2、解题思路

kruskal算法模板题,每一步将最小的边添加,直到添加完n-1条边,如果不足n-1条边,则返回?

3、AC代码

#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MX = 1e3 + 10;
int n, m, pre[MX];
struct node { int u, v, w; }e[MX];
bool cmp(node a, node b) { return a.w < b.w; }
int find(int x) {
	return pre[x] == x ? x : pre[x] = find(pre[x]);
}

int Kruskal() {
	int ans = 0;
	int k = 0;
	for (int i = 1; i <= m; i++) {
		int x = find(e[i].v);
		int y = find(e[i].u);
		if (x != y) {
			pre[x] = y;
			k++;
			ans += e[i].w;
		}
		if (k == n - 1) break;
	}
	if (k == n - 1) return ans;
	else            return 0; //不足n-1条边返回0,输出?
}
signed main()
{
	while (scanf("%lld %lld", &m,&n)) {
		if (m == 0) break;
		for (int i = 1; i <= n; i++) {
			pre[i] = i;
		}

		for (int i = 1; i <= m; i++) {
			scanf("%lld %lld %lld", &e[i].v, &e[i].u, &e[i].w);
		}
		sort(e + 1, e + 1 + m, cmp);
		int ber = Kruskal();
		if (ber) {
			printf("%lld\n", ber);
			continue;
		}
		printf("?\n");
	}
	return 0;
}

B - 畅通工程再续

1、题目描述

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。
Input
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。
Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.
Sample Input
2
2
10 10
20 20
3
1 1
2 2
1000 1000
Sample Output
1414.2
oh!

2、解题思路

相比较于上一题,我们需要将坐标存好,然后计算出合法边(10<=边权<=1000),然后Kruskal算法算出最下生成树即可。

3、AC代码

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int t, c, pre[111], x[111], y[111], cnt;
struct node {
	int u, v;
	double dis;
}g[100010];
bool cmp(node a, node b) {
	return a.dis < b.dis;
}
int find(int x) {
	return pre[x] == x ? x : pre[x] = find(pre[x]);
}
double solve() {
	double ans = 0.0;
	int k = 0;
	for (int i = 1; i <= cnt; i++) {
		int x = find(g[i].v);
		int y = find(g[i].u);
		if (x != y) {
			pre[x] = y;
			k++;
			ans += g[i].dis;
		}
		if (k == c - 1) break;
	}
	if (k == c - 1) return ans;
	else            return 0;
}

signed main()
{
	scanf("%d", &t);

	while (t--) {
		scanf("%d", &c);
		for (int i = 1; i <= c; i++) {
			scanf("%d %d", &x[i], &y[i]);
		}
	    cnt = 0;
		for (int i = 1; i <= c - 1; i++) {
			for (int j = i + 1; j <= c; j++) {
				double dt = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
				//判断是否合法,合法进入边权数组
				if (dt >= 10.0 && dt <= 1000.0) {
					g[++cnt].u = i;
					g[cnt].v = j;
					g[cnt].dis = dt;
				}
			}
		}
		for (int i = 1; i <= c; i++) {
			pre[i] = i;
		}
		sort(g + 1, g + 1 + cnt,cmp);
		double ber = solve();
		if (ber == 0) {
			puts("oh!");
			continue;
		}
		printf("%.1lf\n", ber * 100.0);
	}
	return 0;
}

C - 还是畅通工程

1、题目描述

某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
Sample Output
3
5

Huge input, scanf is recommended.

2、解题思路

模板题,kruskal算法套用即可。

3、AC代码

#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MX = 1e6 + 10;
int n, m, pre[MX];
struct node { int u, v, w; }e[MX];
bool cmp(node a, node b) { return a.w < b.w; }
int find(int x) {
	return pre[x] == x ? x : pre[x] = find(pre[x]);
}

int solve() {
	int ans = 0;
	int k = 0;
	for (int i = 1; i <= m; i++) {
		int x = find(e[i].v);
		int y = find(e[i].u);
		if (x != y) {
			pre[x] = y;
			k++;
			ans += e[i].w;
		}
		if (k == n - 1) break;
	}
	return ans;

}
signed main()
{
	while (scanf("%lld", &n) && n != 0) {
		m = n * (n - 1) / 2;
		for (int i = 1; i <= n; i++) {
			pre[i] = i;
		}
		for (int i = 1; i <= m; i++) {
			scanf("%lld %lld %lld", &e[i].v, &e[i].u, &e[i].w);
		}
		sort(e + 1, e + 1 + m, cmp);
		printf("%lld\n", solve());
	}
	return 0;
}

D - Constructing Roads

1、题目描述

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected.

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.
Input
The first line is an integer N (3 <= N <= 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.
Output
You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum.
Sample Input
3
0 990 692
990 0 179
692 179 0
1
1 2
Sample Output
179

2、解题思路

模板题,他的边权给了一个邻接矩阵,开个二维数组存储即可,然后跑kruskal算法,即可。

3、AC代码

#include <iostream>
#include <algorithm>
using namespace std;
int n, cnt, pre[1000];
int find(int x) {
	return pre[x] == x ? x : pre[x] = find(pre[x]);
}
struct node {
	int b, e, dis;
}g[1000010];
bool cmp(node a, node b) {
	return a.dis < b.dis;
}
int solve() {
	int ber = 0;
	int k = 0;
	for (int i = 0; i < cnt; i++) {
		int x = find(g[i].b);
		int y = find(g[i].e);
		if (x != y) {
			pre[x] = y;
			k++;
			ber += g[i].dis;
		}
		if (k == n - 1) break;
	}
	return ber;
}
int main()
{
	while (~scanf("%d", &n)) {
		for (int i = 1; i <= n; i++) {
			pre[i] = i;
		}
		int tmp;
		cnt = 0;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				scanf("%d", &tmp);
				g[cnt].b = i;
				g[cnt].e = j;
				g[cnt].dis = tmp;
				cnt++;
			}
		}

		int q, x, y; scanf("%d", &q);
		while (q--) {
			scanf("%d%d", &x, &y);
			int fx = find(x);
			int fy = find(y);
			if (fx != fy) {
				pre[fx] = fy;
			}
		}
		sort(g, g + cnt, cmp);
		printf("%d\n", solve());

	}
	return 0;
}

E - Networking

1、题目描述

You are assigned to design network connections between certain points in a wide area. You are given a set of points in the area, and a set of possible routes for the cables that may connect pairs of points. For each possible route between two points, you are given the length of the cable that is needed to connect the points over that route. Note that there may exist many possible routes between two given points. It is assumed that the given possible routes connect (directly or indirectly) each two points in the area.
Your task is to design the network for the area, so that there is a connection (direct or indirect) between every two points (i.e., all the points are interconnected, but not necessarily by a direct cable), and that the total length of the used cable is minimal.
Input
The input file consists of a number of data sets. Each data set defines one required network. The first line of the set contains two integers: the first defines the number P of the given points, and the second the number R of given routes between the points. The following R lines define the given routes between the points, each giving three integer numbers: the first two numbers identify the points, and the third gives the length of the route. The numbers are separated with white spaces. A data set giving only one number P=0 denotes the end of the input. The data sets are separated with an empty line.
The maximal number of points is 50. The maximal length of a given route is 100. The number of possible routes is unlimited. The nodes are identified with integers between 1 and P (inclusive). The routes between two points i and j may be given as i j or as j i.
Output
For each data set, print one number on a separate line that gives the total length of the cable used for the entire designed network.
Sample Input
1 0

2 3
1 2 37
2 1 17
1 2 68

3 7
1 2 19
2 3 11
3 1 7
1 3 5
2 3 89
3 1 91
1 2 32

5 7
1 2 5
2 3 7
2 4 8
4 5 11
3 5 10
1 5 6
4 2 12

0
Sample Output
0
17
16
26

2、解题思路

同样也是一个模板题,跑kruskal算法

3、AC代码

#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MX = 1e6 + 10;
int n, m, pre[MX];
struct node { int u, v, w; }e[MX];
bool cmp(node a, node b) { return a.w < b.w; }
int find(int x) {
	return pre[x] == x ? x : pre[x] = find(pre[x]);
}

int solve() {
	int ans = 0;
	int k = 0;
	for (int i = 1; i <= m; i++) {
		int x = find(e[i].v);
		int y = find(e[i].u);
		if (x != y) {
			pre[x] = y;
			k++;
			ans += e[i].w;
		}
		if (k == n - 1) break;
	}
	return ans;

}
signed main()
{
	while (true) {
		cin >> n;
		if (n == 0)break;
		cin >> m;
		if (m == 0) {
			cout << 0 << endl;
			continue;
		}
		for (int i = 1; i <= n; i++) {
			pre[i] = i;
		}
		for (int i = 1; i <= m; i++) {
			scanf_s("%lld %lld %lld", &e[i].v, &e[i].u, &e[i].w);
		}
		sort(e + 1, e + 1 + m, cmp);
		printf("%lld\n", solve());
	}
	return 0;
}

F - Building a Space Station

1、题目描述

You are a member of the space station engineering team, and are assigned a task in the construction process of the station. You are expected to write a computer program to complete the task.
The space station is made up with a number of units, called cells. All cells are sphere-shaped, but their sizes are not necessarily uniform. Each cell is fixed at its predetermined position shortly after the station is successfully put into its orbit. It is quite strange that two cells may be touching each other, or even may be overlapping. In an extreme case, a cell may be totally enclosing another one. I do not know how such arrangements are possible.

All the cells must be connected, since crew members should be able to walk from any cell to any other cell. They can walk from a cell A to another cell B, if, (1) A and B are touching each other or overlapping, (2) A and B are connected by a `corridor’, or (3) there is a cell C such that walking from A to C, and also from B to C are both possible. Note that the condition (3) should be interpreted transitively.

You are expected to design a configuration, namely, which pairs of cells are to be connected with corridors. There is some freedom in the corridor configuration. For example, if there are three cells A, B and C, not touching nor overlapping each other, at least three plans are possible in order to connect all three cells. The first is to build corridors A-B and A-C, the second B-C and B-A, the third C-A and C-B. The cost of building a corridor is proportional to its length. Therefore, you should choose a plan with the shortest total length of the corridors.

You can ignore the width of a corridor. A corridor is built between points on two cells’ surfaces. It can be made arbitrarily long, but of course the shortest one is chosen. Even if two corridors A-B and C-D intersect in space, they are not considered to form a connection path between (for example) A and C. In other words, you may consider that two corridors never intersect.
Input
The input consists of multiple data sets. Each data set is given in the following format.

n
x1 y1 z1 r1
x2 y2 z2 r2

xn yn zn rn

The first line of a data set contains an integer n, which is the number of cells. n is positive, and does not exceed 100.

The following n lines are descriptions of cells. Four values in a line are x-, y- and z-coordinates of the center, and radius (called r in the rest of the problem) of the sphere, in this order. Each value is given by a decimal fraction, with 3 digits after the decimal point. Values are separated by a space character.

Each of x, y, z and r is positive and is less than 100.0.

The end of the input is indicated by a line containing a zero.
Output
For each data set, the shortest total length of the corridors should be printed, each in a separate line. The printed values should have 3 digits after the decimal point. They may not have an error greater than 0.001.

Note that if no corridors are necessary, that is, if all the cells are connected without corridors, the shortest total length of the corridors is 0.000.
Sample Input
3
10.000 10.000 50.000 10.000
40.000 10.000 50.000 10.000
40.000 40.000 50.000 10.000
2
30.000 30.000 30.000 20.000
40.000 40.000 40.000 20.000
5
5.729 15.143 3.996 25.837
6.013 14.372 4.818 10.671
80.115 63.292 84.477 15.120
64.095 80.924 70.029 14.881
39.472 85.116 71.369 5.553
0
Sample Output
20.000
0.000
73.834

2、解题思路

这次的点变化成了三维的,如果这个球相互接触或者重叠,他们就算相连,计算边权的时候减去两个球的半径,如果小于0,则说明这两个球不用修路直接连接,直接将连接值赋值为0,然后跑出最小生成树就行!!!

3、AC代码

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
struct node
{
	int u, v;
	double w;
}a[100002];
struct node1
{
	double x, y, z, r;
}b[110002];
int fa[100002];
int findd(int x)
{
	if (x != fa[x])return fa[x] = findd(fa[x]);
	return fa[x];
}
int cmp(node x, node y)
{
	return x.w < y.w;
}
int hb(int a, int b)
{
	int fx = findd(a);
	int fy = findd(b);
	if (fx != fy)
	{
		fa[fx] = fy;
		return 1;
	}
	return 0;
}
double cmp1(node1 aa, node1 bb)
{
	double tmp= (sqrt((aa.x - bb.x) * (aa.x - bb.x) + (aa.y - bb.y) * (aa.y - bb.y) + (aa.z - bb.z) * (aa.z - bb.z)) - (aa.r + bb.r));
	return tmp >= 0 ? tmp : 0;
}
int main()
{
	int n;
	while (cin >> n)
	{
		if (n == 0)break;
		int ans = 0, k = 0;
		double sum = 0;
		for (int i = 0; i < n; i++)
		{
			fa[i] = i;
		}
		for (int i = 0; i < n; i++)
		{
			cin >> b[i].x >> b[i].y >> b[i].z >> b[i].r;
			for (int j = 0; j < i; j++)
			{
				double jl = cmp1(b[i], b[j]);
				a[k].u = i;
				a[k].v = j;
				a[k].w = jl;
				k++;
			}
		}
		sort(a, a + k, cmp);
		for (int i = 0; i < k; i++)
		{
			if (hb(a[i].u, a[i].v))
			{
				if (a[i].w > 0)
				{
					sum += a[i].w;
				}
			}
		}
		printf("%.3lf\n", sum);
	}
}

G - Truck History

1、题目描述

2、解题思路

给出的第一行字符串是原始的字符串,其他字符串是由这个字符串变化而成的,之间的变化值为两个字符串之间字符不同的个数,即为边权,题意就是寻找从第一个字符串生成其他字符串花的最小步数,即最小生成树。

3、AC代码

#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
char s[2010][10];
int n,mp[2010][2010], vis[100000],dis[10000];
int cnt(int a, int b){
    
    int num = 0;
    for (int i = 0; i < 7; i++)  {
        if (s[a][i] != s[b][i])   
            num++;
    }
    return num;
}


void prime() { 
    for (int i = 1; i <= n; i++)
        dis[i] = mp[1][i];
    int min;
 
    int ans = 0;

    dis[1] = 0;
    vis[1] = 1;
    for (int i = 1; i < n; ++i){
        min = INF;
        int k;
        for (int j = 1; j <= n; ++j) {
            if (!vis[j] && min > dis[j]){
                min = dis[j];
                k = j;
            }
        }
        vis[k] = 1;
        ans = ans + min;
        for (int j = 1; j <= n; ++j) {
            if (!vis[j] && dis[j] > mp[k][j])
                dis[j] = mp[k][j];
        }
    }
    printf("The highest possible quality is 1/%d.\n", ans);

}


int main() {
 
    while (scanf_s("%d", &n)&& n) {
        
        memset(dis, INF, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        memset(mp, INF, sizeof(mp));
        for (int i = 1; i <= n; i++) {
            cin >> s[i];
            for (int j = 0; j < i; j++) {
 
                mp[i][j] = mp[j][i] = cnt(i, j);
                
            }
        }
        prime();
    }
}

H - Arctic Network

1、题目描述

The Department of National Defence (DND) wishes to connect several northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver and some outposts will in addition have a satellite channel.
Any two outposts with a satellite channel can communicate via the satellite, regardless of their location. Otherwise, two outposts can communicate by radio only if the distance between them does not exceed D, which depends of the power of the transceivers. Higher power yields higher D but costs more. Due to purchasing and maintenance considerations, the transceivers at the outposts must be identical; that is, the value of D is the same for every pair of outposts.

Your job is to determine the minimum D required for the transceivers. There must be at least one communication path (direct or indirect) between every pair of outposts.
Input
The first line of input contains N, the number of test cases. The first line of each test case contains 1 <= S <= 100, the number of satellite channels, and S < P <= 500, the number of outposts. P lines follow, giving the (x,y) coordinates of each outpost in km (coordinates are integers between 0 and 10,000).
Output
For each case, output should consist of a single line giving the minimum D required to connect the network. Output should be specified to 2 decimal points.
Sample Input
1
2 4
0 100
0 300
0 600
150 750
Sample Output
212.13

2、解题思路

这道题求解的是p-1-s条边的最大值,-s是因为,有s个卫星帮助哨站通信,用一个数组存边,prim算法解决,最后输出第p-1-s即可

3、AC代码

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
double map[10010][10010];
double vis[10010], dis[10010], x[10010], y[10010];
int main(){
	int t;
	scanf("%d", &t);
	while (t--){
		memset(vis, 0, sizeof(vis));
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= m; i++)
			scanf("%lf%lf", &x[i], &y[i]);
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= m; j++){
				map[i][j] = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
			}
		}
			
		for (int i = 1; i <= m; i++)
			dis[i] = map[1][i];
		vis[1] = 1;
		int cnt = 1;
		int k;
		while (cnt < m){
			int min = 9999999;
			for (int i = 1; i <= m; i++){
				if (vis[i] == 0 && dis[i] < min){
					min = dis[i];
					k = i;
				}
			}
			cnt++;
			vis[k] = 1;
			for (int i = 1; i <= m; i++){
				if (vis[i] == 0 && dis[i] > map[i][k])
					dis[i] = map[i][k];
			}
		}
		sort(dis + 1, dis + m + 1);
		printf("%.2lf\n", dis[m - n + 1]);
	}
}

I - Highways

1、题目描述

The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a very poor system of public highways. The Flatopian government is aware of this problem and has already constructed a number of highways connecting some of the most important towns. However, there are still some towns that you can’t reach via a highway. It is necessary to build more highways so that it will be possible to drive between any pair of towns without leaving the highway system.

Flatopian towns are numbered from 1 to N and town i has a position given by the Cartesian coordinates (xi, yi). Each highway connects exaclty two towns. All highways (both the original ones and the ones that are to be built) follow straight lines, and thus their length is equal to Cartesian distance between towns. All highways can be used in both directions. Highways can freely cross each other, but a driver can only switch between highways at a town that is located at the end of both highways.

The Flatopian government wants to minimize the cost of building new highways. However, they want to guarantee that every town is highway-reachable from every other town. Since Flatopia is so flat, the cost of a highway is always proportional to its length. Thus, the least expensive highway system will be the one that minimizes the total highways length.
Input
The input consists of two parts. The first part describes all towns in the country, and the second part describes all of the highways that have already been built.

The first line of the input file contains a single integer N (1 <= N <= 750), representing the number of towns. The next N lines each contain two integers, xi and yi separated by a space. These values give the coordinates of ith town (for i from 1 to N). Coordinates will have an absolute value no greater than 10000. Every town has a unique location.

The next line contains a single integer M (0 <= M <= 1000), representing the number of existing highways. The next M lines each contain a pair of integers separated by a space. These two integers give a pair of town numbers which are already connected by a highway. Each pair of towns is connected by at most one highway.
Output
Write to the output a single line for each new highway that should be built in order to connect all towns with minimal possible total length of new highways. Each highway should be presented by printing town numbers that this highway connects, separated by a space.

If no new highways need to be built (all towns are already connected), then the output file should be created but it should be empty.
Sample Input
9
1 5
0 0
3 2
4 5
5 1
0 4
5 2
1 2
5 3
3
1 3
9 7
1 2
Sample Output
1 6
3 7
4 9
5 7
8 3

2、解题思路

我们可以开两个结构体,一个存输入的城市的坐标,下标就是城市编号。另一个结构体存第i号城市到j号城市的距离,并存i,j,我们把每个城市之间的距离遍历一遍,用克鲁斯卡尔算法跑一遍即可,若没有相连,则输出,否则跳过。

3、AC代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
using namespace std;
struct node
{
	int x;
	int y;
	double id;
};
node s[3515100];
node p[3515100];
node u[3515100];
int f[1500000];
bool cmp(node a, node b)
{
	return a.id < b.id;
}
bool cmp1(node a, node b)
{
	return a.x < b.x;
}
int find(int x)
{
	if (f[x] != x)
	{
		f[x] = find(f[x]);
	}
	return f[x];
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	scanf_s("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf_s("%d%d", &s[i].x, &s[i].y);
	}
	int o = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)
		{
			double x = s[i].x - s[j].x;
			double y = s[i].y - s[j].y;
			p[o].x = i;
			p[o].y = j;
			p[o].id = sqrt(x * x + y * y);
			o++;
		}
	}
	for (int i = 1; i <= n; i++)
	{
		f[i] = i;
	}
	int m;
	scanf_s("%d", &m);
	for (int i = 1; i <= m; i++)
	{
		int a, b;
		scanf_s("%d%d", &a, &b);
		int x = find(a);
		int y = find(b);
		if (x != y)
		{
			swap(x, y);
			f[x] = y;
		}
	}
	sort(p + 1, p + o, cmp);
	cout << endl;
	for (int i = 1; i <= o; i++)
	{
		int x = find(p[i].x);
		int y = find(p[i].y);
		if (x != y)
		{
			swap(x, y);
			f[x] = y;
			printf("%d %d\n", p[i].x, p[i].y);
		}
	}
}

J - Agri-Net

1、题目描述

Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.
The distance between any two farms will not exceed 100,000.
Input
The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.
Output
For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.
Sample Input
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
Sample Output
28

2、解题思路

简单的模板题,遍历点之间的距离,然后用克鲁斯卡尔或者prim算法模板即可。

3、AC代码

#include <iostream>
#include <algorithm>
using namespace std;
int a[150][150];
struct node
{
	int x;
	int y;
	int id;
};
node s[150000];
int f[1500000];
bool cmp(node a, node b)
{
	return a.id < b.id;
}
int find(int x)
{
	if (f[x] != x)
	{
		f[x] = find(f[x]);
	}
	return f[x];
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	while (cin >> n)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				cin >> a[i][j];
			}
		}
		int o = 1;
		for (int i = 1; i <= n; i++)
		{
			for (int j = i+1; j <= n; j++)
			{
				s[o].x = i;
				s[o].y = j;
				s[o].id = a[i][j];
				o++;
			}
		}
		for (int i = 1; i <= n; i++)
		{
			f[i] = i;
		}
		sort(s + 1, s + o, cmp);
		long long ans = 0;
		for (int i = 1; i <= o; i++)
		{
			int x = find(s[i].x);
			int y = find(s[i].y);
			if (x != y)
			{
				swap(x, y);
				f[x] = y;
				ans += s[i].id;
			}
		}
		cout << ans << endl;
	}
}

K - Borg Maze

1、题目描述

The Borg is an immensely powerful race of enhanced humanoids from the delta quadrant of the galaxy. The Borg collective is the term used to describe the group consciousness of the Borg civilization. Each Borg individual is linked to the collective by a sophisticated subspace network that insures each member is given constant supervision and guidance.

Your task is to help the Borg (yes, really) by developing a program which helps the Borg to estimate the minimal cost of scanning a maze for the assimilation of aliens hiding in the maze, by moving in north, west, east, and south steps. The tricky thing is that the beginning of the search is conducted by a large group of over 100 individuals. Whenever an alien is assimilated, or at the beginning of the search, the group may split in two or more groups (but their consciousness is still collective.). The cost of searching a maze is definied as the total distance covered by all the groups involved in the search together. That is, if the original group walks five steps, then splits into two groups each walking three steps, the total distance is 11=5+3+3.
Input
On the first line of input there is one integer, N <= 50, giving the number of test cases in the input. Each test case starts with a line containg two integers x, y such that 1 <= x,y <= 50. After this, y lines follow, each which x characters. For each character, a space '' stands for an open space, a hash mark#’’ stands for an obstructing wall, the capital letter A'' stand for an alien, and the capital letterS’’ stands for the start of the search. The perimeter of the maze is always closed, i.e., there is no way to get out from the coordinate of the ``S’’. At most 100 aliens are present in the maze, and everyone is reachable.
Output
For every test case, output one line containing the minimal cost of a succesful search of the maze leaving no aliens alive.
Sample Input

2
6 5
#####
#A#A##
# # A#
#S  ##
#####
7 7
#####  
#AAA###
#    A#
# S ###
#     #
#AAA###
#####  

Sample Output

8
11

2、解题思路

题目的题意就是求连接所有A和S的最小生成树,我们用bfs把图(结点与结点之间的最短距离)跑出来,然后跑kruskal算法即可,有个需要注意的地方,输入的时候字符用gets()函数读取,gets读取空格,不读取换行符。

3、AC代码

#include <iostream>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MX = 1e3;
int pre[MX * MX];
int m, n, k;
int vis[MX][MX], g[MX][MX];
char s[MX][MX], s1[MX];
int dir[4][2] = { {1,0},{-1,0},{0,-1},{0,1} };
struct bian
{
    int u, v, w;
} a[MX * MX];
struct node
{
    int x, y, step;
} cur, nex;
int cmp(bian x, bian y)
{
    return x.w < y.w;
}
int find(int x) {
    return pre[x] == x ? x : pre[x] = find(pre[x]);
}
int join(int a, int b){
    int x, y;
    x = find(a);
    y = find(b);
    if (x == y)
        return 0;
    pre[y] = x;
    return 1;
}
void bfs(int x, int y, int ans){
    memset(vis, 0, sizeof vis);
    queue<node>Q;
    cur.x = x;
    cur.y = y;
    cur.step = 0;
    vis[x][y] = 1;
    Q.push(cur);
    while (!Q.empty()) {
        cur = Q.front();
        Q.pop();
        for (int i = 0; i < 4; i++) {
            nex.x = cur.x + dir[i][0];
            nex.y = cur.y + dir[i][1];
            nex.step = cur.step + 1;
            if (nex.x >= 0 && nex.y >= 0 && nex.x < n && nex.y < m && vis[nex.x][nex.y] == 0 && g[nex.x][nex.y] != -1) {
                vis[nex.x][nex.y] = 1;
                Q.push(nex);
                if (g[nex.x][nex.y] > 0){
                    a[k].u = ans;
                    a[k].v = g[nex.x][nex.y];
                    a[k++].w = nex.step;
                }
            }
        }
    }
}
int main()
{
    int t;   scanf("%d", &t);
   
    while (t--){
        int i, j, sum = 0, u = 1;
        scanf("%d%d", &m, &n);
        memset(g, 0, sizeof g);
        gets(s1);
        for (i = 0; i < n; i++){
            gets(s[i]);
        }
        k = 0;
        for (i = 0; i < n; i++){
            for (j = 0; j < m; j++){
                if (s[i][j] == ' ')
                    g[i][j] = 0;
                if (s[i][j] == '#')
                    g[i][j] = -1;
                if (s[i][j] == 'A' || s[i][j] == 'S'){
                    g[i][j] = u;
                    u++;
                }
            }
        }

        for (i = 0; i < n; i++){
            for (j = 0; j < m; j++){
                if (g[i][j] > 0)
                    bfs(i, j, g[i][j]);
            }
        }

        for (i = 0; i <= u; i++)
            pre[i] = i;
        sort(a, a + k, cmp);
        for (i = 0; i < k; i++) {
            if (join(a[i].u, a[i].v)){
                sum += a[i].w;
            }
        }
        printf("%d\n", sum);
    }
    return 0;
}

L - The Unique MST

1、题目描述

Given a connected undirected graph, tell if its minimum spanning tree is unique.

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V’, E’), with the following properties:

  1. V’ = V.
  2. T is connected and acyclic.

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E’) of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E’.
Input
The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.
Output
For each input, if the MST is unique, print the total cost of it, or otherwise print the string ‘Not Unique!’.
Sample Input
2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2
Sample Output
3
Not Unique!

2、解题思路

题意就是证明最小生成树的总权值在整个图中是否唯一,我们每次封掉(去掉)最小生成树中的一条边,然后跑一次,看有没有权值相同的最小生成树,如果有输出Not unique,无则输出mst的值。

3、AC代码

#include<iostream>
#include<algorithm>
using namespace std;
const int MX = 120;
struct bian {
	int u, v, w;
}e[MX * MX];
int n, m, flag, ans, pre[MX];
bool cmp(bian a, bian b) { return a.w < b.w; }
int find(int x) {
	return pre[x] == x ? x : pre[x] = find(pre[x]);
}
int join(int x, int y) {
	int fx = find(x);
	int fy = find(y);
	if (fx != fy) {
		pre[fx] = fy;
		return 1;
	}
	return 0;
}
void ks() {
	ans = 0;
	int cnt = 0;
	int mp[MX * MX];

	for (int i = 0; i < m; i++) {
		if (join(e[i].u, e[i].v)) {
			mp[cnt++] = i;
			ans += e[i].w;
		}
	}

	for (int i = 0; i < cnt; i++) {
		for (int i = 1; i <= n; i++) {
			pre[i] = i;
		}
		int rans = 0, rcnt = 0;
		for (int j = 0; j < m; j++) {
			if (j == mp[i])  continue;

			if (join(e[j].u, e[j].v)) {
				rans += e[j].w;
				rcnt++;
			}
		}
		if (rcnt == n - 1 && rans == ans){
			flag = 0;
			return;
		}
	}
}
int main()
{
	int t;   scanf("%d", &t);
	while (t-- && scanf("%d %d",&n,&m)) {
		for (int i = 0; i < m; i++) {
			scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
		}
		flag = 1;

		for (int i = 1; i <= n; i++) {
			pre[i] = i;
		}
		sort(e, e + m, cmp);

		ks();

		if (flag) printf("%d\n", ans);
		else      printf("Not Unique!\n");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值