PTA图论的搜索题

news/2024/5/3 15:45:05

目录

7-1 列出连通集

题目

输入格式:

输出格式:

输入样例:

输出样例:

AC代码

7-2 六度空间

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码

7-3 地下迷宫探索

题目

输入格式:

输出格式:

输入样例1:

输出样例1:

输入样例2:

输出样例2:

思路

AC代码

7-4 社交网络图中结点的“重要性”计算

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码

7-5 List Components

题目

Input Specification:

Output Specification:

Sample Input:

Sample Output:

思路

AC代码

7-6 排座位

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码

7-7 红色警报

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码

7-8 家庭房产

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码

7-9 肿瘤诊断

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码(BFS)

没有AC的代码(调了很久,还是2/30)。

7-10 图着色问题

题目

输入格式:

输出格式:

输入样例:

输出样例:

思路

AC代码

7-11 拯救007

输入格式:

输出格式:

输入样例 1:

输出样例 1:

输入样例 2:

输出样例 2:

思路

AC代码


7-1 列出连通集

题目

分数 25

作者 陈越

单位 浙江大学

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:

输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:

按照"{ v1​ v2​ ... vk​ }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

输入样例:

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

输出样例:

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

AC代码

#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
int mat[11][11];
bool visited[12];
vector<int> v;
void dfs(int cur,int n)
{visited[cur]=true;v.push_back(cur);for(int i=0;i<n;i++){if(visited[i]==true||i==cur)continue;if(mat[cur][i]==1)dfs(i,n);}
}
void bfs(int cur,int n)
{queue<int> Q;Q.push(cur);visited[cur]=true;v.push_back(cur);//v存放cur所在的连通集while(!Q.empty()){int k=Q.size();for(int i=0;i<k;i++){//取队头元素的所有直接联通点for(int j=0;j<n;j++){if(visited[j]==true||Q.front()==j)continue;if(mat[Q.front()][j]==1){Q.push(j);visited[j]=true;v.push_back(j);}}Q.pop();}}
}
int main()
{int n,e;cin>>n>>e;for(int i=0;i<e;i++){int a,b;cin>>a>>b;mat[a][b]=mat[b][a]=1;}memset(visited,false,sizeof(visited)/sizeof(bool));//dfsfor(int i=0;i<n;i++){v.resize(0);if(visited[i]==false)dfs(i,n);for(int j=0;j<v.size();j++){if(j==0)cout<<"{ ";cout<<v[j]<<" ";if(j==v.size()-1)cout<<"}\n";}}//bfsmemset(visited,false,sizeof(visited)/sizeof(bool));for(int i=0;i<n;i++){v.resize(0);if(visited[i]==false)bfs(i,n);for(int j=0;j<v.size();j++){if(j==0)cout<<"{ ";cout<<v[j]<<" ";if(j==v.size()-1)cout<<"}\n";}}
}

7-2 六度空间

题目

分数 30

作者 DS课程组

单位 浙江大学

“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”如图1所示。


图1 六度空间示意图

“六度空间”理论虽然得到广泛的认同,并且正在得到越来越多的应用。但是数十年来,试图验证这个理论始终是许多社会学家努力追求的目标。然而由于历史的原因,这样的研究具有太大的局限性和困难。随着当代人的联络主要依赖于电话、短信、微信以及因特网上即时通信等工具,能够体现社交网络关系的一手数据已经逐渐使得“六度空间”理论的验证成为可能。

假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。

输入格式:

输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤103,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N编号)。

输出格式:

对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。

输入样例:

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

输出样例:

1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%

代码长度限制

16 KB

时间限制

2500 ms

内存限制

64 MB

思路

广度优先搜索,通过几层的搜索能找到另一人就是两个人之间的间隔。

AC代码

这题是刚学数据结构时写的,里面有一些复杂的结构。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define MVNum 1000
#define Maxint 32767
using namespace std;
bool visited[MVNum];
typedef int VerTexType;
typedef int ArcType;//邻接表
typedef struct ArcNode {//边 int adjvex;  //边所指向顶点的位置 struct ArcNode* nextarc; //下一个边 
}ArcNode;
typedef struct VNode {//顶点 VerTexType date;ArcNode* firstarc;
}VNode, AdjList[MVNum];
typedef struct {  //邻接表 AdjList vertices;int vexnum, arcnum;
}ALGraph;void CreateUDG(ALGraph& G)
{//创建无向图的邻接表 cin >> G.vexnum >> G.arcnum;//顶点赋初值 for (int i = 0; i < G.vexnum; i++){G.vertices[i].date = i + 1;G.vertices[i].firstarc = NULL;}for (int k = 0; k < G.arcnum; k++){int i, j;cin >> i >> j;i--;j--;ArcNode* p1, * p2;//i邻接一条边j p1 = new ArcNode;p1->adjvex = j;p1->nextarc = G.vertices[i].firstarc;G.vertices[i].firstarc = p1;//j邻接一条边ip2 = new ArcNode;p2->adjvex = i;p2->nextarc = G.vertices[j].firstarc;G.vertices[j].firstarc = p2;}
}
double BFS_AL(ALGraph& G, int v)
{//从下标为V的点开始广度优先搜索,对邻接表 
//	cout << "从下标" << v << "开始查找:";int friends = 0;int step = 0;//节点之间的距离 memset(visited, false, sizeof(bool) * G.vexnum);queue<VNode>Q;  //队列的元素是邻接表的点,不是邻接表边Q.push(G.vertices[v]);visited[v] = true;while (!Q.empty() && step < 6){step++;
//		cout << "\n第" << step << "步访问的下标:";//取队里的所有点,并将这些元素的未标记的邻接点放进队列int n = Q.size();for (int i = 0; i < n; i++){VNode p = Q.front();Q.pop();//找出队元素所有未被访问的邻接点 (即找某个人的所有朋友)ArcNode* q = p.firstarc;while (q != NULL){if (visited[q->adjvex] == false){visited[q->adjvex] = true;Q.push(G.vertices[q->adjvex]);}q = q->nextarc;}}}//while//计算比例 ,六步之内找到的朋友(包括自己)/总人数 for (int i = 0; i < G.vexnum; i++)if (visited[i] == true) friends++;
//	cout << "vexnum=" << G.vexnum << "  " << "friends=" << friends << "  ";return 1.0 * friends / G.vexnum;
}int main()
{ALGraph G;CreateUDG(G);for (int i = 0; i < G.vexnum; i++){double a = 100 * BFS_AL(G, i);printf("%d: %.2lf%%\n", i + 1, a);}return 0;
}

7-3 地下迷宫探索

题目

分数 30

作者 DS课程组

单位 浙江大学

地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式。地道网是房连房、街连街、村连村的地下工事,如下图所示。

我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智。在现在和平发展的年代,对多数人来说,探索地下通道或许只是一种娱乐或者益智的游戏。本实验案例以探索地下通道迷宫作为内容。

假设有一个地下通道迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关。请问你如何从某个起点开始在迷宫中点亮所有的灯并回到起点?

输入格式:

输入第一行给出三个正整数,分别表示地下迷宫的节点数N(1<N≤1000,表示通道所有交叉点和端点)、边数M(≤3000,表示通道数)和探索起始节点编号S(节点从1到N编号)。随后的M行对应M条边(通道),每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:

若可以点亮所有节点的灯,则输出从S开始并以S结束的包含所有节点的序列,序列中相邻的节点一定有边(通道);否则虽然不能点亮所有节点的灯,但还是输出点亮部分灯的节点序列,最后输出0,此时表示迷宫不是连通图。

由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以节点小编号优先的次序访问(点灯)。在点亮所有可以点亮的灯后,以原路返回的方式回到起点。

输入样例1:

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

输出样例1:

1 2 3 4 5 6 5 4 3 2 1

输入样例2:

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

输出样例2:

6 4 5 4 6 0

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

思路

深度优先搜索。但是这题并不是说每个节点只遍历一次,而是说在遍历完所有的节点的过程中,访问某个节点和访问完这个节点回溯时都要打印一次。

AC代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int SIZE = 1005;
int N, M, S;
int cnt = 0; //记录输出的数量,防止多输出空格
vector<vector<int>> arc;
vector<int> path;
int visited[SIZE];
void inif()
{arc.resize(N + 1);for (int i = 0; i < M; i++){int arc1, arc2;cin >> arc1 >> arc2;arc[arc1].push_back(arc2);arc[arc2].push_back(arc1);}//排序,优先访问序列小的节点for (int i = 1; i <= N; i++){sort(arc[i].begin(), arc[i].end());}
}
void dfs(int i)
{visited[i] = 1;cnt++;//点灯时输出一次if (cnt == 1) cout << i;else cout << " " << i;for (int j = 0; j < arc[i].size(); j++){if (visited[arc[i][j]] == 0){dfs(arc[i][j]);//点完相邻的灯后输出一次cout << " " << i;}}
}
int main()
{cin >> N >> M >> S;inif();dfs(S);if(cnt!=N) cout<<" 0";
}

7-4 社交网络图中结点的“重要性”计算

题目

分数 30

作者 DS课程组

单位 浙江大学

在社交网络中,个人或单位(结点)之间通过某些关系(边)联系起来。他们受到这些关系的影响,这种影响可以理解为网络中相互连接的结点之间蔓延的一种相互作用,可以增强也可以减弱。而结点根据其所处的位置不同,其在网络中体现的重要性也不尽相同。

“紧密度中心性”是用来衡量一个结点到达其它结点的“快慢”的指标,即一个有较高中心性的结点比有较低中心性的结点能够更快地(平均意义下)到达网络中的其它结点,因而在该网络的传播过程中有更重要的价值。在有N个结点的网络中,结点vi​的“紧密度中心性”Cc(vi​)数学上定义为vi​到其余所有结点vj​ (j=i) 的最短距离d(vi​,vj​)的平均值的倒数:

对于非连通图,所有结点的紧密度中心性都是0。

给定一个无权的无向图以及其中的一组结点,计算这组结点中每个结点的紧密度中心性。

输入格式:

输入第一行给出两个正整数N和M,其中N(≤104)是图中结点个数,顺便假设结点从1到N编号;M(≤105)是边的条数。随后的M行中,每行给出一条边的信息,即该边连接的两个结点编号,中间用空格分隔。最后一行给出需要计算紧密度中心性的这组结点的个数K(≤100)以及K个结点编号,用空格分隔。

输出格式:

按照Cc(i)=x.xx的格式输出K个给定结点的紧密度中心性,每个输出占一行,结果保留到小数点后2位。

输入样例:

9 14
1 2
1 3
1 4
2 3
3 4
4 5
4 6
5 6
5 7
5 8
6 7
6 8
7 8
7 9
3 3 4 9

输出样例:

Cc(3)=0.47
Cc(4)=0.62
Cc(9)=0.35

代码长度限制

16 KB

时间限制

20000 ms

内存限制

64 MB

思路

用广度优先搜索计算某个点到其他点的距离。其间用一个数记录联通点的数量,若联通点的数量不等于N,就全输出0。

AC代码

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int MAXSIZE=10005;
int N,M,K;
vector<vector<int>> f;   //用于记忆化
vector<vector<int>> arcs; //邻接表
int visited[MAXSIZE];
bool flag=true;  //标志是否连通
int cnt=0;      //联通点的数量
void inif()
{cin>>N>>M;arcs.resize(N+1);for(int i=0;i<M;i++){int arc1,arc2;cin>>arc1>>arc2;arcs[arc1].push_back(arc2);arcs[arc2].push_back(arc1);}
}
void MEMSET(){for(int i=1;i<=N;i++) visited[i]=0;}
long long bfs(int x)
{if(!flag) return -1;MEMSET();long long sum=0;int length=0;//点x到某个点的长度queue<int> q;q.push(x);visited[x]=1;cnt=1;while(!q.empty()){int size=q.size();++length;for(int i=0;i<size;i++){int cur=q.front();q.pop();for(auto arc:arcs[cur]){if(visited[arc]==0){q.push(arc);++cnt;visited[arc]=1;sum+=length;}}}}if(cnt!=N){flag=false;return -1;}return sum;
}
void slove()
{cin>>K;for(int i=0;i<K;i++){if(i!=0) cout<<endl;int x;cin>>x;if(!flag){cout<<"Cc("<<x<<")=0.00";continue;}double aver=1.0*(N-1)/bfs(x);if(!flag){cout<<"Cc("<<x<<")=0.00";continue;}printf("Cc(%d)=%.2lf",x,aver);}
}
int main()
{inif();slove();
}

7-5 List Components

题目

分数 25

作者 陈越

单位 浙江大学

For a given undirected graph with N vertices and E edges, please list all the connected components by both DFS (Depth First Search) and BFS (Breadth First Search). Assume that all the vertices are numbered from 0 to N-1. While searching, assume that we always start from the vertex with the smallest index, and visit its adjacent vertices in ascending order of their indices.

Input Specification:

Each input file contains one test case. For each case, the first line gives two integers N (0<N≤10) and E, which are the number of vertices and the number of edges, respectively. Then E lines follow, each described an edge by giving the two ends. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in each line a connected component in the format { v1​ v2​ ... vk​ }. First print the result obtained by DFS, then by BFS.

Sample Input:

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

Sample Output:

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

思路

这是一个英文题,稍微阅读一下然后和7-1的输入输出对比一下会发现,这题就是7-1的英文版。

AC代码

#include<iostream>
#include<queue>
using namespace std;
int f[15][15];
int visited[15];
int N, E;
vector<int> g;
int flag = false;
void dfs(int i)
{for (int j = 0; j < N; j++) {if (f[i][j] == 1 && visited[j] == 0) {g.push_back(j);visited[j] = 1;dfs(j);}}
}
void bfs(int i)
{queue<int> q;q.push(i);g.push_back(i);visited[i] = 1;while (!q.empty()) {int cur = q.front();q.pop();for (int j = 0; j < N; j++) {if (f[cur][j] == 1 && visited[j] == 0) {visited[j] = 1;g.push_back(j);q.push(j);}}}
}
int main()
{cin >> N >> E;for (int i = 0; i < E; i++) {int x, y;cin >> x >> y;f[x][y] = f[y][x] = 1;}for (int i = 0; i < N; i++) {if (visited[i] == 0) {visited[i] = 1;g.resize(0);g.push_back(i);dfs(i);if (flag == true) cout << endl;flag = true;cout << "{ ";for (int j = 0; j < g.size(); j++) {cout << g[j] << " ";}cout << "}";}}for (int i = 0; i < N; i++) visited[i] = 0;for (int i = 0; i < N; i++) {if (visited[i] == 0) {g.resize(0);bfs(i);if (flag == true) cout << endl;flag = true;cout << "{ ";for (int j = 0; j < g.size(); j++) {cout << g[j] << " ";}cout << "}";}}
}

7-6 排座位

题目

分数 25

作者 陈越

单位 浙江大学

布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。

输入格式:

输入第一行给出3个正整数:N(≤100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系,其中关系为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。

这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

输出格式:

对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...;如果他们之间只有敌对关系,则输出No way

输入样例:

7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2

输出样例:

No problem
OK
OK but...
No way

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

思路

并查集判断两个人是否是朋友(的朋友的朋友的朋友……)。

AC代码

#include<iostream>
using namespace std;
const int MAXSIZE = 105;
int N, M, K;
int relation[MAXSIZE][MAXSIZE];
int fa[MAXSIZE * MAXSIZE];
int find(int x)
{int r = x;while (fa[r] != r){fa[r] = fa[fa[r]];r = fa[r];}return r;
}
void merge(int x, int y)
{int fx = find(x);int fy = find(y);if (fx > fy) {fa[fy] = fx;}else {fa[fx] = fy;}
}
int node(int i, int j) { return N * (i - 1) + j; }
void inif()
{cin >> N >> M >> K;for (int i = 1; i <= N; i++) {fa[i] = i;for (int j = 1; j <= N; j++) {relation[i][j] = 0;}}for (int i = 0; i < M; i++){int x, y, c;cin >> x >> y >> c;relation[x][y] = relation[y][x] = c;if (c == 1) merge(x, y);}
}
void slove()
{for (int i = 0; i < K; i++){if (i != 0) cout << endl;int x, y;cin >> x >> y;bool flag = (find(x) == find(y));if (flag && relation[x][y] != -1) cout << "No problem";else if (!flag && relation[x][y] != -1) cout << "OK";else if (flag && relation[x][y] == -1) cout << "OK but...";else cout << "No way";}
}
int main()
{inif();slove();
}

7-7 红色警报

题目

分数 25

作者 陈越

单位 浙江大学

战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。

输入格式:

输入在第一行给出两个整数N(0 < N ≤ 500)和M(≤ 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。

注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。

输出格式:

对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.

输入样例:

5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3

输出样例:

City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

思路

构建好图后先记录一次连通集个数。随后每删除一个点就更新一次连通集个数。若连通集个数没变或只是减了一个,则说明没有改变整个国家的连通性。

AC代码

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int MAXSIZE = 505;
int N, M, K;
vector<vector<int>> g;
int book[MAXSIZE];
int lost[MAXSIZE];//==1表示已经失去
int unionCount = 0;
int func()
{int sum = 0;for (int i = 0; i < N; i++) book[i] = 0;for (int i = 0; i < N; i++) {if (book[i] == 1 || lost[i] == 1) continue;sum++;queue<int> q;q.push(i);while (!q.empty()) {int cur = q.front();q.pop();for (int j = 0; j < g[cur].size(); j++) {int node = g[cur][j];if (lost[node] == 1 || book[node] == 1) continue;q.push(node);book[node] = 1;}}}return sum;
}
void slove()
{cin >> K;int aim;for (int i = 0; i < K; i++) {cin >> aim;if (i != 0) cout << endl;lost[aim] = 1;int cnt = func();if (cnt == unionCount || cnt == unionCount - 1) {cout << "City " << aim << " is lost.";}else {cout << "Red Alert: City " << aim << " is lost!";}unionCount = cnt;//更新if (i == N - 1) {cout << "\nGame Over.";}}
}
int main()
{cin >> N >> M;g.resize(N);for (int i = 0; i < M; i++) {int x, y;cin >> x >> y;g[x].push_back(y);g[y].push_back(x);}unionCount = func();slove();//cout << unionCount;
}

7-8 家庭房产

题目

分数 25

作者 陈越

单位 浙江大学

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:

编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积

其中编号是每个人独有的一个4位数的编号;分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0≤k≤5)是该人的子女的个数;孩子i是其子女的编号。

输出格式:

首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

输入样例:

10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100

输出样例:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

思路

这题要是一开始就告诉你出现过的人有几个并且所有人的编号都为1-N,那么这题就不难。难点就是所有人的编号是离散的,就要一些特殊处理。

我们用并查集来判断家庭的个数,每次合并两个人的时候,将编号大的指向编号小的。这样统计面积的时候就只需要将每个点的面积属性加到father数组的根当中即可。最后将家庭按照面积降序、最小编号升序的方式排序,然后输出。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int MAXSIZE=1e5+5;
int N;
int family=0;
int fa[MAXSIZE];
bool visited[MAXSIZE];
struct new_person{int id,fid,mid,num,area,k;int child[6];
} g[1005];
struct _ans{int minid=0,people=0;double num=0,area=0;bool have=false;
} ans[MAXSIZE];
bool cmp(_ans a,_ans b)
{if(a.area==b.area)return a.minid<b.minid;return a.area>b.area;
}
int find(int x)
{int r=x;while(fa[r]!=r) r=fa[r];return r;
}
void merge(int x,int y)
{int fx=find(x);int fy=find(y);if(fx<fy) fa[fy]=fx;else if(fx>fy) fa[fx]=fy;
}
int main()
{cin>>N;for(int i=0;i<MAXSIZE;i++) fa[i]=i;//处理输入数据for(int i=0;i<N;i++){cin>>g[i].id>>g[i].fid>>g[i].mid>>g[i].k;visited[g[i].id]=true;if(g[i].fid!=-1){visited[g[i].fid]=true;merge(g[i].id,g[i].fid);}if(g[i].mid!=-1){visited[g[i].mid]=true;merge(g[i].id,g[i].mid);}for(int j=0;j<g[i].k;j++){cin>>g[i].child[j];visited[g[i].child[j]]=true;merge(g[i].id,g[i].child[j]);}cin>>g[i].num>>g[i].area;}//统计房产和每个家庭最小idfor(int i=0;i<N;i++){int j=find(g[i].id);ans[j].minid=j;ans[j].num+=g[i].num;  //房产个数ans[j].area+=g[i].area;  //房产面积 ans[j].have=true;}//统计每个家庭人数和家庭个数for(int i=0;i<10000;i++){if(visited[i]) ans[find(i)].people++;if(ans[i].have) family++;}//将房产个数和房产面积转换为平均值for(int i=0;i<10000;i++){if(ans[i].have){ans[i].num=(double)(1.0*ans[i].num/ans[i].people);ans[i].area=(double)(1.0*ans[i].area/ans[i].people);}}//排序并输出sort(ans,ans+10000,cmp);cout<<family;for(int i=0;i<family;i++){printf("\n%04d %d %.3lf %.3lf",ans[i].minid,ans[i].people,ans[i].num,ans[i].area);}
}

7-9 肿瘤诊断

题目

分数 30

作者 陈越

单位 浙江大学

在诊断肿瘤疾病时,计算肿瘤体积是很重要的一环。给定病灶扫描切片中标注出的疑似肿瘤区域,请你计算肿瘤的体积。

输入格式:

输入第一行给出4个正整数:M、N、L、T,其中M和N是每张切片的尺寸(即每张切片是一个M×N的像素矩阵。最大分辨率是1286×128);L(≤60)是切片的张数;T是一个整数阈值(若疑似肿瘤的连通体体积小于T,则该小块忽略不计)。

最后给出L张切片。每张用一个由0和1组成的M×N的矩阵表示,其中1表示疑似肿瘤的像素,0表示正常像素。由于切片厚度可以认为是一个常数,于是我们只要数连通体中1的个数就可以得到体积了。麻烦的是,可能存在多个肿瘤,这时我们只统计那些体积不小于T的。两个像素被认为是“连通的”,如果它们有一个共同的切面,如下图所示,所有6个红色的像素都与蓝色的像素连通。

输出格式:

在一行中输出肿瘤的总体积。

输入样例:

3 4 5 2
1 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
0 0 1 1
1 0 1 1
0 1 0 0
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
0 0 0 1
0 0 0 1
1 0 0 0

输出样例:

26

代码长度限制

16 KB

时间限制

1000 ms

内存限制

64 MB

思路

刚开始看不懂题目什么意思,后面发现,就是一个图结构,要我们判断所有体积大于T的连通块。

但是以往的邻接矩阵都是二维的,有四个方向。这次是三维的,有六个方向。

AC代码(BFS)

#include<iostream>
#include<queue>
using namespace std;
int M, N, L, T;
struct Node {int x, y, z;
};
int dx[6] = { 1,-1,0,0,0,0 };
int dy[6] = { 0,0,1,-1,0,0 };
int dz[6] = { 0,0,0,0,1,-1 };
int f[1300][130][70];
int book[1300][130][70];
int sum = 0;
int bfs(int x, int y, int z)
{int ans = 1;queue<Node> q;q.push({ x,y,z });while (!q.empty()) {Node node = q.front();q.pop();//遍历六个方向for (int i = 0; i < 6; i++) {int new_x = node.x + dx[i];int new_y = node.y + dy[i];int new_z = node.z + dz[i];if (new_x < 0 || new_x >= M || new_y < 0 || new_y >= N || new_z < 0 || new_z >= L || book[new_x][new_y][new_z] == 1 || f[new_x][new_y][new_z] == 0)continue;ans++;book[new_x][new_y][new_z] = 1;q.push({ new_x,new_y,new_z });}}if (ans >= T) return ans;else return 0;
}
int main()
{cin >> M >> N >> L >> T;for (int i = 0; i < L; i++)for (int j = 0; j < M; j++)for (int k = 0; k < N; k++)cin >> f[j][k][i];for (int i = 0; i < L; i++)for (int j = 0; j < M; j++)for (int k = 0; k < N; k++)if (f[j][k][i] == 1 && book[j][k][i] == 0) {book[j][k][i] = 1;sum += bfs(j, k, i);}cout << sum << endl;return 0;
}

没有AC的代码(调了很久,还是2/30)。

只有一个点2分,其他点都是运行超时或者内存超限。将BFS的倒数第七句的[tz][tz][ty]改成[tz][tx][ty]还是只有6分。又发现错误的大佬可以指正一下。

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int M, N, L, T;
int f[61][1287][130];
bool visited[61][1287][130];
//上下前后左右六个方向
int dx[6] = { 0,0,-1,1,0,0 };
int dy[6] = { 0,0,0,0,-1,1 };
int dz[6] = { -1,1,0,0,0,0 };
struct coord {int x, y, z;
};
int bfs(int x_, int y_, int z_)
{int ans = 1;queue<coord> q;//{z,x,y}coord p = { x_,y_,z_ };q.push(p);visited[z_][x_][y_] = 1;while (!q.empty()) {coord cur = q.front();q.pop();int x = cur.x;int y = cur.y;int z = cur.z;for (int i = 0; i < 6; i++) {int tx = x + dx[i];int ty = y + dy[i];int tz = z + dz[i];if (tx >= 0 && tx < M && ty >= 0 && ty < N && tz >= 0 && tz < L && visited[tz][tx][ty] == false && f[tz][tx][ty] == 1) {coord adj = { tx,ty,tz };q.push(adj);visited[tz][tz][ty] = 1;ans++;}}}return ans;
}
int main()
{cin >> M >> N >> L >> T;for (int i = 0; i < L; i++) {for (int j = 0; j < M; j++) {for (int k = 0; k < N; k++) {cin >> f[i][j][k];}}}int sum = 0;/*int sum1 = sizeof(f) / sizeof(int);int sum2 = sizeof(visited) / sizeof(int);cout << sum1 << endl << sum2 << endl;*/for (int i = 0; i < L; i++) {for (int j = 0; j < M; j++) {for (int k = 0; k < N; k++) {if (visited[i][j][k] == 1 || f[i][j][k] == 0) continue;int v = bfs(i, j, k);sum += (v >= T ? v : 0);}}}cout << sum;
}

7-10 图着色问题

题目

分数 25

作者 陈越

单位 浙江大学

图着色问题是一个著名的NP完全问题。给定无向图G=(V,E),问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?

但本题并不是要你解决这个着色问题,而是对给定的一种颜色分配,请你判断这是否是图着色问题的一个解。

输入格式:

输入在第一行给出3个整数V(0<V≤500)、E(≥0)和K(0<K≤V),分别是无向图的顶点数、边数、以及颜色数。顶点和颜色都从1到V编号。随后E行,每行给出一条边的两个端点的编号。在图的信息给出之后,给出了一个正整数N(≤20),是待检查的颜色分配方案的个数。随后N行,每行顺次给出V个顶点的颜色(第i个数字表示第i个顶点的颜色),数字间以空格分隔。题目保证给定的无向图是合法的(即不存在自回路和重边)。

输出格式:

对每种颜色分配方案,如果是图着色问题的一个解则输出Yes,否则输出No,每句占一行。

输入样例:

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

输出样例:

Yes
Yes
No
No

代码长度限制

16 KB

时间限制

300 ms

内存限制

64 MB

思路

以此判断每个点是否有颜色相同的相邻点。甚至不用搜索。

关键点是每一个方案颜色只能有K种(刚好K种)。

AC代码

//只用k种颜色,不多不少
#include<iostream>
#include<vector>
#include<map>
#include<queue>
using namespace std;
int V,E,K;
vector<vector<int>> g;
int color[502];
int main()
{cin>>V>>E>>K;g.resize(V+1);for(int i=0;i<E;i++){int x,y;cin>>x>>y;g[x].emplace_back(y);g[y].emplace_back(x);}int n;cin>>n;while(n--){map<int,int> mp;for(int i=1;i<=V;i++){cin>>color[i];mp[color[i]]++;}int color_cnt=mp.size();if(color_cnt!=K){cout<<"No\n";continue;}bool flag=true;for(int i=1;i<=V;i++){for(int j=0;j<g[i].size();j++){if(color[i]==color[g[i][j]]){flag=false;goto loop;}}}loop:;if(flag) cout<<"Yes\n";else cout<<"No\n";}
}

7-11 拯救007

分数 25

作者 陈越

单位 浙江大学

在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑袋跳上岸去!(据说当年替身演员被最后一条鳄鱼咬住了脚,幸好穿的是特别加厚的靴子才逃过一劫。)

设鳄鱼池是长宽为100米的方形,中心坐标为 (0, 0),且东北角坐标为 (50, 50)。池心岛是以 (0, 0) 为圆心、直径15米的圆。给定池中分布的鳄鱼的坐标、以及007一次能跳跃的最大距离,你需要告诉他是否有可能逃出生天。

输入格式:

首先第一行给出两个正整数:鳄鱼数量 N(≤100)和007一次能跳跃的最大距离 D。随后 N 行,每行给出一条鳄鱼的 (x,y) 坐标。注意:不会有两条鳄鱼待在同一个点上。

输出格式:

如果007有可能逃脱,就在一行中输出"Yes",否则输出"No"。

输入样例 1:

14 20
25 -15
-25 28
8 49
29 15
-35 -2
5 28
27 -29
-8 -28
-20 -35
-25 -20
-13 29
-30 15
-35 40
12 12

输出样例 1:

Yes

输入样例 2:

4 13
-12 12
12 12
-12 -12
12 -12

输出样例 2:

No

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

思路

用BFS判断能不能走到鳄鱼池旁边即可。

两个点相邻的依据。两个点的距离<=D。

输入时将所有能在池心岛一脚跳过去的点入队。

AC代码

#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
int N, D;
int book[110];
struct Node {int x, y;int i;
};
queue<Node> q;
vector<Node> g;
bool flag = false;
void bfs()
{while (!q.empty()) {Node node = q.front();q.pop();for (int i = 0; i < N; i++) {if (book[i] == 1 || i == node.i) continue;int dx = abs(g[i].x - node.x);int dy = abs(g[i].y - node.y);int dis = dx * dx + dy * dy;if (dis <= D * D) {q.push(g[i]);book[i] = 1;int minedgex = min(abs(g[i].x - 50), abs(g[i].x + 50));int minedgey = min(abs(g[i].y - 50), abs(g[i].y + 50));if (minedgex <= D || minedgey <= D) { flag = true; return; }}}}
}
int main()
{cin >> N >> D;double maxdis = (7.5 + D) * (7.5 + D);//处理输入,先将能从池心岛一步跳往的点入队for (int i = 0; i < N; i++) {int x, y;cin >> x >> y;g.push_back({ x,y,i });if (x * x + y * y <= maxdis) {q.push({ x,y,i });book[i] = 1;//该点距离鳄鱼池左右边界的最短距离int minedgex = min(abs(x - 50), abs(x + 50));//该点距离鳄鱼池上下边界的最短距离int minedgey = min(abs(y - 50), abs(y + 50));if (minedgex <= D || minedgey <= D) { flag = true; }}}if(!flag) bfs();if (flag) cout << "Yes";else cout << "No";
}

//


http://www.mrgr.cn/p/03601770

相关文章

SQL刷题---2021年11月每天新用户的次日留存率

解题思路&#xff1a; 1.首先算出每个新用户注册的日期,将其命名为表a select uid,min(date(in_time)) dt from tb_user_log group by uid2.计算出每个用户登录的天数,将其命名为表b select uid,date(in_time) dt from tb_user_log union select uid,date(out_time) dt fro…

Anaconda Navigator启动卡在loading applications界面(同时莫名启动了VSCODE)

0.问题 参考:anaconda navigator启动时一直卡在 loading applications 页面 我的问题和网上普遍的不太一样, 首先我能找到conda_api.py, 但是不是在D:\anaconda\Lib\site-packages\anaconda_navigator\api文件夹下,而是在...\anaconda3\pkgs\anaconda-project-0.11.1-py311haa9…

C盘越用越大?教你如何科学管理C盘空间

前言&#xff1a; 如图&#xff0c;左边是我多开的E5电脑&#xff0c;装的是LTSC2019_210707F多开封装版&#xff0c;C盘占用8.5GB&#xff0c;右边是我平常打游戏写代码的电脑&#xff0c;装的是Win11 22H2&#xff0c;C盘占用30GB。两台电脑都关闭了休眠&#xff0c;C盘的虚拟…

STM32学习和实践笔记(15):STM32中断系统

中断概念 CPU执行程序时&#xff0c;由于发生了某种随机的事件(外部或内部)&#xff0c;引起CPU暂 时中断正在运行的程序&#xff0c;转去执行一段特殊的服务程序(中断服务子程序 或中断处理程序)&#xff0c;以处理该事件&#xff0c;该事件处理完后又返回被中断的程序 继…

Edge崩溃(Edge错误代码STATUS_ACCESS_DENIED的修复方法)

0.问题 今天由于在编写自动化脚本,edge浏览器自动填充表单功能十分烦人,会导致测试失败遂在选择每次关闭时清除浏览数据时, 全选了所有选项(后来发现实际上只需要删除自动填充表单即可)然后重启edge后,坏事来了,首先旁边提示...扩展出错,请重新加载,而且所有网页(包括setting设…

解决 Win11 微软拼音输入法下 JetBrains IDE Shift+F6 失效的问题

如果你使用 Win11 系统下的微软拼音输入法,同时又在使用 JetBrains 系列的 IDE,你可能会发现 "Refactor -> Rename..." 功能对应的默认快捷键 Shift+F6 按了之后没有反应,但通过菜单执行这个操作是正常的。这个问题目前基本可以确定是微软拼音输入法引起的。 目…

C# 动态加载dll

方式1 using System; using System.Reflection;class Program {static void Main(){string dllPath "path/to/your/library.dll"; // 替换为你的DLL文件路径Assembly myAssembly Assembly.LoadFile(dllPath);Type myType myAssembly.GetType("YourNamespace…

4.19第二天冲刺

晨会1.人员:袁兴兰、齐飞跃、王瑞2.会议讨论袁兴兰:1)昨天完成寻找免费api,完成博客的整理2)今天打算收集数据,美化页面3)没有遇到问题 齐飞跃:1)昨天学习调用第三方库或第三方api2)今天完成优化api返回的结果3)没有遇到问题王瑞:1)昨天完成画出安卓前端页面2)今…

重复组合理论与公式

从n个球当中,取出k个球,k个球允许重复出现,问有几种可能。 解答: 假设现在有编号的n个球,每一个编号的球有个,那么会有等式: ,现在问题就转化为该等式一共有多少解? 这里使用间隔法,即使用(n-1)个分隔符分隔得到n个空间,使得每一个空间之和为k. 假设这里一共有5个球…

【C语言】【数据结构】项目实践——贪吃蛇游戏(超详细)

前言 本篇博客我们来实现一个小游戏项目——贪吃蛇&#xff0c;相信肯定很多人都玩过&#xff0c;那么整个贪吃蛇是怎么实现出来的那&#xff0c;这个项目用到了很多方面的知识&#xff1a;C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。我们就通过这…

MySQL-05.存储引擎

C-05.存储引擎 为了方便管理,把连接管理,查询缓存,语法解析,查询优化这些不涉及真实数据存储的功能划分为MySQL Server的功能,把真实存取数据的功能划分为存储引擎的功能。所以在MySQL Server完成了查询优化后,只需按照生成的执行计划调用底层存储引擎提供的API,获取到数…

一文玩转Seaborn热力图中调色板设置

1.引言 在前文中我们介绍了如何利用Seaborn绘制热力图&#xff0c;并详细介绍了各种热力图中的控制条件。本文重点介绍如何控制绘制热力图中的调色板。 闲话少说&#xff0c;我们直接开始吧&#xff01; 2.举个栗子 我们首先来看个上一节的栗子&#xff0c;代码如下&#x…

前三次大作业总结

一、前言 这三次作业都是完成一个答题判题程序,但是每一次的都在增加新的内容,所以难度逐次增加。 1.第一次作业 程序输入三部分内容:题目数量、题目内容、答题信息。设计类并根据所输入的信息使用正则表达式进行切割,把每一部分存进各个对象中的属性中并调用函数进行判题。…

CentOS如何使用Docker部署Plik服务并实现公网访问本地设备上传下载文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

(十八)C++自制植物大战僵尸游戏的游戏暂停实现

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/uzrnw 游戏暂停 当玩家遇到突发事件&#xff0c;可以通过暂停功能暂停游戏&#xff0c;以便及时处理问题。在激烈的游戏中&#xff0c;玩家可能需要暂停游戏来进行策略调整。此外&#xff0c;长时间的游戏对战可能会让玩…

如何下载省,市,区县行政区Shp数据

摘要&#xff1a;一般非专业的GIS应用通常会用到省市等行政区区划边界空间数据做分析&#xff0c;本文简单介绍了如何在互联网上下载省&#xff0c;市&#xff0c;区县的shp格式空间边界数据&#xff0c;并介绍了一个好用的在线数据转换工具&#xff0c;并且开源。 目录 一、下…

牛客小白月赛91 (小白被虐记)

A.Bingbong的化学世界(签到题) 思路: 你会发现当 a[1][4] == . 是是 o-甲乙苯 a[6][4] == | 是是 p-甲乙苯 另外则是m-甲乙苯 Code:#include<bits/stdc++.h>using namespace std;const int N = 10;char a[N][N];int main() {ios::sync_with_stdio(false); cin.tie(0); …

优先队列 存 结构体--重载运算符

参考:priority_queue在结构体中的使用_priority_queue 结构体-CSDN博客

FTP客户端Transmit 5 for Mac中文激活版

Transmit 5是一款功能强大的Mac FTP客户端软件&#xff0c;它由Panic公司开发&#xff0c;为用户提供简单、高效的文件传输体验。 Transmit 5 for Mac中文激活版下载 Transmit 5支持多种传输协议&#xff0c;如FTP、SFTP、WebDAV和Amazon S3等&#xff0c;满足用户不同的文件传…

Transformer中的位置编码详解

什么是位置编码 位置编码概述 位置编码的目的是为了补充序列的位置信息&#xff0c;这是因为自注意力机制本身不包含位置的概念&#xff08;例如顺序信息&#xff09;。位置编码的具体作用是&#xff0c;对于不同的输入序列成分&#xff0c;赋予其不同的位置标识&#xff0c;确…