ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

数据结构荣誉课第五次上机测试

2021-06-02 20:04:26  阅读:172  来源: 互联网

标签:结点 数据结构 上机 int head 第五次 Edge link include


数据结构荣誉课第五次上机测试

7-1 图的深度优先搜索I (100 分)

无向图 G 有 n 个顶点和 m 条边。求图G的深度优先搜索树(森林)以及每个顶点的发现时间和完成时间。每个连通分量从编号最小的结点开始搜索,邻接顶点选择顺序遵循边的输入顺序。

在搜索过程中,第一次遇到一个结点,称该结点被发现;一个结点的所有邻接结点都搜索完,该结点的搜索被完成。深度优先搜索维护一个时钟,时钟从0开始计数,结点被搜索发现或完成时,时钟计数增1,然后为当前结点盖上时间戳。一个结点被搜索发现和完成的时间戳分别称为该结点的发现时间和完成时间。

输入格式:

第1行,2个整数n和m,用空格分隔,分别表示顶点数和边数, 1≤n≤50000, 1≤m≤100000.

第2到m+1行,每行两个整数u和v,用空格分隔,表示顶点u到顶点v有一条边,u和v是顶点编号,1≤u,v≤n.

输出格式:

第1到n行,每行两个整数di和fi,用空格分隔,表示第i个顶点的发现时间和完成时间1≤i≤n 。

第n+1行,1个整数 k ,表示图的深度优先搜索树(森林)的边数。

第n+2到n+k+1行,每行两个整数u和v,表示深度优先搜索树(森林)的一条边<u,v>,边的输出顺序按 v 结点编号从小到大。
作者 : 谷方明
单位: 吉林大学
代码长度限制:16 KB
时间限制:200 ms
内存限制:10 MB

输入样例:

在这里给出一组输入。例如:

6 5
1 3
1 2
2 3
4 5
5 6

输出样例:

在这里给出相应的输出。例如:

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

思路:题目要看懂
1.每个连通分量要从最小的边开始:开循环从i=1开始DFS;
2.在搜索过程中,第一次遇到一个结点,称该结点被发现;一个结点的所有邻接结点都搜索完,该结点的搜索被完成:就是在进入DFS后另开始时间戳dfn[v]为++top,在该点DFS完全结束后令Last[v]=++top,最后统一输出就行。
3.第n+2到n+k+1行,每行两个整数u和v,表示深度优先搜索树(森林)的一条边<u,v>,边的输出顺序按 v 结点编号从小到大:利用sort函数将结构体数组排序,重载比较符号。

代码如下:

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
vector<int>mp[100001];
int visited[100001];
int dfn[100001];//开始时间戳
int Last[100001];//结束时间戳
int top = 0;//时间戳计数器
int top1 = 0;//边数计数器,与e数组配套
struct edge
{
	int u;
	int v;
	bool operator<(const struct edge&a)const
	{
		return v < a.v;
	}
}e[100001];
void DFS(int v)
{
	if (visited[v])return;
	else
	{
		visited[v] = 1;
		dfn[v] = ++top;//开始时间戳
		for (int i = 0; i < mp[v].size(); i++)
		{
			int k = mp[v][i];
			if (!visited[k])
			{
				e[++top1].u = v;
				e[top1].v = k;//存到边数组以供最后边的输出
				DFS(k);
			}	
		}
		Last[v] = ++top;//结束时间戳
	}
}
int main()
{
	int m, n;
	scanf("%d%d", &m, &n);
	for (int i = 1; i <= n; i++)
	{
		int from, to;
		scanf("%d%d", &from, &to);
		mp[from].push_back(to);
		mp[to].push_back(from);
	}//建图
	for (int i = 1; i <= m; i++)
		DFS(i);//循环DFS
	for (int i = 1; i <= m; i++)
	{
		printf("%d %d\n", dfn[i], Last[i]);
	}//打印时间戳
	printf("%d\n", top1);
	sort(e + 1, e + 1 + top1);//后边排序
	for (int i = 1; i <= top1; i++)
	{
		printf("%d %d\n", e[i].u, e[i].v);
	}
	return 0;
}

反思:我觉得这题难点在读题。

7-2 圆 (100 分)

二维平面上有n 个圆。请统计:这些圆形成的不同的块的数目。

圆形成的块定义如下:
(1)一个圆是一个块;
(2)若两个块有公共部分(含相切),则这两个块形成一个新的块,否则还是两个不同的块。

输入格式:

第1行包括一个整数n,表示圆的数目,n<=8000

第2到n+1行,每行3 个用空格隔开的数x,y,r。(x,y)是圆心坐标,r 是半径。所有的坐标及半径都是不大于30000 的非负整数。

输出格式:

1个整数,表示形成的块的数目。

输入样例:

在这里给出一组输入。例如:

2
0 0 1
1 0 2

输出样例:

在这里给出相应的输出。例如:

1

作者:谷方明
单位:吉林大学
代码长度限制:16 KB
时间限制:500 ms
内存限制:5 MB

思路:并查集为最优解,每输入一个⚪就和前面的⚪判断是否相交或者相切,如果father不同,就Union两者,这时不能break,因为每个⚪可以和多个⚪相交,而将多个块连成一个块。

代码如下:

#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
struct circle
{
	int x;
	int y;
	int r;
}c[10000];
vector<int>mp[10000];
int father[10000];
int find(int v)
{
	if (father[v] == v)
		return v;
	else
		return find(father[v]);
}//找代表元
void Union(int x,int y)
{
	int fx = find(x);
	int fy = find(y);
	if (fx != fy)
    {
       father[fx] = fy;
    }
}//合并算法
int main()
{
	int m;
	scanf("%d", &m);
	scanf("%d%d%d", &c[1].x, &c[1].y, &c[1].r);
	father[1] = 1;
	for (int i = 2; i <= m; i++)
	{
		scanf("%d%d%d", &c[i].x, &c[i].y, &c[i].r);
		father[i] = i;
		for (int j = i-1; j >= 1; j--)
		{
			if ((long long)(c[i].r + c[j].r)*(c[i].r + c[j].r) >=
			 (long long)((c[i].x - c[j].x)*(c[i].x - c[j].x) + 
			 (c[i].y - c[j].y)*(c[i].y - c[j].y)))//这里要强制类型转换要不然某个10的样例点过不去。
			{
				Union(j, i);
			}
		}
	}//一边循环一边插入判断。
	int count1 = 0;
	for (int i = 1; i <= m; i++)
	{
		if (father[i] == i)count1++;
	}
	printf("%d", count1);
		return 0;
}

反思:注意long long。

7-3 供电 (100 分)

要给N个地区供电。每个地区或者建一个供电站,或者修一条线道连接到其它有电的地区。试确定给N个地区都供上电的最小费用。

输入格式:

第1行,两个个整数 N 和 M , 用空格分隔,分别表示地区数和修线路的方案数,1≤N≤100000≤M≤50000

第2行,包含N个用空格分隔的整数P[i],表示在第i个地区建一个供电站的代价,1 ≤P[i]≤ 100,0001≤i≤N

接下来M行,每行3个整数a、b和c,用空格分隔,表示在地区a和b之间修一条线路的代价为c,1 ≤ c ≤ 100,0001≤a,b≤N

输出格式:

一行,包含一个整数, 表示所求最小代价。

输入样例:
在这里给出一组输入。例如:

4 6
5 4 4 3
1 2 2
1 3 2
1 4 2
2 3 3
2 4 3
3 4 4

输出样例:

在这里给出相应的输出。例如:

9

作者:谷方明
单位:吉林大学
代码长度限制:16 KB
时间限制:500 ms
内存限制:10 MB

思路:本题很显然是一道最小生成树问题,但是即存在边权又存在点权,所以我们要将n个点的点权都转换成边权,然后再采用最小生成树的算法来得到支撑子树,然后将每条边权相加(仅需要遍历),得到结果。建议使用prim的堆优化或者是kruskal算法,反正我的非堆优化Prim算法O(n2)没有过。

标签:结点,数据结构,上机,int,head,第五次,Edge,link,include
来源: https://blog.csdn.net/qq_56208478/article/details/117477592

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有