内容为武汉大学国家网络安全学院2022级大一第三学期“996”实训课程中所做的笔记,仅供个人复习使用,如有侵权请联系本人,将与15个工作日内将博客设置为仅粉丝可见。
目录
交易会
- 时间限制:1000ms
- 空间限制:131072K
- 语言限制:C语言
A 厂最近举办了一场大型的交易会。交易会上共有 n 家店铺参与(编号为 1 到 n),当然这些店铺也会参与交易。如果店铺 a 购买了店铺 b 的产品,就算生成一桩交易,且每桩交易 a 都会向 b 支付 c 万元。现想问哪家店铺,参与交易总额最大。
交易总额 = 交易总收入 + 交易总支出
输入格式
第一行时输入两个整数:n,m(1≤n,m≤10^5),分别表示参与交易的店铺总数和交易总数。
接下来 m 行每行三个整数:a,b,c(1≤a,b≤n),表示店铺 a 向 b 支付了 c 万元。保证 c 的取值在 `int` 范围内。
注意:两家店铺可能会多次交易,且没有两家店铺是同一家的情况。
输出格式
输出 1 行一个整数结果,表示参与交易总额最大的那所店铺的编号。
如果两家交易总额相同,输出编号更小的。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
10000 2
1 2 1
2 4 2
样例输出
2
我的答案
#include <stdio.h>
#define MAXN 100005
long long shop[MAXN]; // 存储每个店铺的交易总额
int main() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
shop[i] = 0; // 初始化每个店铺的交易总额为0
}
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
shop[a] += c; // 店铺a的支出增加c
shop[b] += c; // 店铺b的收入增加c
}
int max_shop = 1;
for (int i = 2; i <= n; i++) {
if (shop[i] > shop[max_shop]) {
max_shop = i; // 找出交易总额最大的店铺
}
}
printf("%d\n", max_shop); // 输出交易总额最大的店铺的编号
return 0;
}
朋友的距离
- 时间限制:1000ms
- 内存限制:131072K
- 语言限制:C语言
有一群朋友,一共有 n 个人,他们都生活在不同的城市。他们生活在一个非对称世界里面,也就是说 a 到 b 的距离不一定等于 b 到 a 的距离。
有一天,他们的世界变回了对称世界,这个时候,任意两个人 a,b 之间的距离变成了 a 到 b 的距离和 b 到 a 的距离中的最大值。
输入格式
输入第一行一个整数 n(1≤n≤100) 表示图的点数。
接下里 n 行,每行输入 n 的整数,表示这个图的邻接矩阵。
保证对角线上的数字都为 0。
输出格式
输入一共 n 行,每行 n 个整数,表示回到对称世界以后的邻接矩阵。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
3
0 6 0
1 0 1
9 1 0
样例输出
0 6 9
6 0 1
9 1 0
我的答案
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
int matrix[n][n];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
scanf("%d", &matrix[i][j]);
}
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (matrix[i][j] < matrix[j][i])
{
matrix[i][j] = matrix[j][i];
}
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
邻接表使用
- 时间限制:1000ms
- 内存限制:32768K
- 语言限制:C语言
这一节我们来复习下前面刚学的邻接表的使用。给出一个包含有向图和无向图的混合图 G,图上有 n 个点和 m 条边,现在你需要使用邻接表来存储该混合图 G 并按格式输出邻接表。
输入格式
输入第一行为两个正整数 n 和 m(1≤n,m≤100),表示混合图上的 n 个点和 m 条边。
接下来输入 m 行,每行输入三个整数 a,x,y(0≤a≤1,0≤x,y<n),表示点 x 和点 y 之间有一条边。如果 a=0,则表示该边为有向边,如果 a=1,则表示该边为无向边。
输出格式
输出邻接表,输出 n 行,第 i 行表示第 i 个点连接边的情况,首先输出 i,接着输出:
,然后输出所有点 i 能到达的点的编号,边关系中后出现的点先输出。每个整数前有一个空格,具体格式见样例。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
4 4
0 0 1
1 0 2
0 3 1
1 2 3
样例输出
0: 2 1
1:
2: 3 0
3: 2 1
我的答案
#include <stdio.h>
#include <stdlib.h>
typedef struct Edge
{
int to;
struct Edge *next;
} Edge;
Edge *addEdge(Edge *head, int to)
{
Edge *newEdge = (Edge *)malloc(sizeof(Edge));
newEdge->to = to;
newEdge->next = head;
return newEdge;
}
int main()
{
int n, m;
scanf("%d %d", &n, &m);
Edge *adj[n];
for (int i = 0; i < n; i++)
{
adj[i] = NULL;
}
for (int i = 0; i < m; i++)
{
int a, x, y;
scanf("%d %d %d", &a, &x, &y);
if (a == 0)
{
adj[x] = addEdge(adj[x], y);
}
else
{
adj[x] = addEdge(adj[x], y);
adj[y] = addEdge(adj[y], x);
}
}
for (int i = 0; i < n; i++)
{
printf("%d: ", i);
Edge *cur = adj[i];
while (cur != NULL)
{
printf("%d ", cur->to);
cur = cur->next;
}
printf("\n");
}
return 0;
}
关系查询
- 时间限制:1000ms
- 内存限制:131072K
- 语言限制:C语言
输入 n 对朋友关系,朋友关系是相互的。a 是 b 的朋友,b 也是 a 的朋友。
然后有 m 次查询,每次查询询问 a 和 b 是否是朋友。
输入格式
第一行输入一个整数 n(1≤n≤100)。
接下来 n 行,每行输入两个名字,表示一对朋友关系。
接下来一行输入一个整数 m(1≤m≤100),表示 m 个查询。
接下来 m 行,每行输入两个名字,表示一次查询。
输入中的名字只包含大小写字母,长度不超过 20。
输出格式
对于每次查询,如果他们是朋友,输出一行"Yes"
,否则输出一行"No"
。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
5
Mary Tom
Islands Barty
Andy Amy
Islands Amy
Tom Mary
3
Amy Andy
Islands Tom
Islands Barty
样例输出
Yes
No
Yes
我的答案
#include <stdio.h>
#include <string.h>
//定义一个结构体,表示朋友关系
typedef struct {
char name1[21]; //第一个名字
char name2[21]; //第二个名字
} Friend;
//定义一个函数,判断两个名字是否相等
int equal(char *a, char *b) {
return strcmp(a, b) == 0;
}
//定义一个函数,判断两个朋友关系是否相等
int friend_equal(Friend *a, Friend *b) {
return (equal(a->name1, b->name1) && equal(a->name2, b->name2)) || (equal(a->name1, b->name2) && equal(a->name2, b->name1));
}
//定义一个函数,判断两个名字是否是朋友
int is_friend(Friend *friends, int n, char *a, char *b) {
//创建一个临时的朋友关系
Friend temp;
strcpy(temp.name1, a);
strcpy(temp.name2, b);
//遍历所有的朋友关系,看是否有和临时的朋友关系相等的
for (int i = 0; i < n; i++) {
if (friend_equal(&friends[i], &temp)) {
return 1; //找到了,返回1
}
}
return 0; //没有找到,返回0
}
int main() {
int n; //输入的朋友关系数目
scanf("%d", &n); //读入n
Friend friends[n]; //创建一个数组,存储所有的朋友关系
for (int i = 0; i < n; i++) {
scanf("%s %s", friends[i].name1, friends[i].name2); //读入每一对朋友关系
}
int m; //输入的查询数目
scanf("%d", &m); //读入m
for (int i = 0; i < m; i++) {
char a[21], b[21]; //创建两个变量,存储每一次查询的两个名字
scanf("%s %s", a, b); //读入每一次查询的两个名字
if (is_friend(friends, n, a, b)) { //调用is_friend函数,判断是否是朋友
printf("Yes\n"); //如果是,输出"Yes"
} else {
printf("No\n"); //如果不是,输出"No"
}
}
return 0;
}
p 节点
- 时间限制:1000ms
- 空间限制:131072K
- 语言限制:C语言
给出一颗有向树,总共 n 个节点,如果一个节点的度不小于它所有的儿子以及他的父亲的度(如果存在父亲或者儿子),那么我们称这个点为 p 节点,现在给你一棵树你需要统计出 p 节点的个数。
输入格式
输入的第一行包含一个整数 t(1≤t≤100),表示数据组数。
接下来 t 组数据,每组数据第一行一个数 n(1≤n≤1000),表示树的节点数。
然后 n−1 行,每行两个数 x,y(0<x,y<n),代表 y 是 x 的儿子节点,两数之间以一个空格分隔。
输出格式
输出 t 行,每一行一个整数,代表 p 节点的个数。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
1
5
1 2
1 3
1 4
4 5
样例输出
1
题解:建立一个无向图,然后遍历每个点与他直接相连的点,比较度数大小。
我的答案
#include <stdio.h>
#include <string.h>
int father[1005]; // 存储每个节点的父亲
int degree[1005]; // 存储每个节点的度数
int main()
{
int t; // 数据组数
scanf("%d", &t);
while (t--)
{
int n; // 树的节点数
scanf("%d", &n);
memset(father, 0, sizeof(father)); // 初始化父亲数组为0
memset(degree, 0, sizeof(degree)); // 初始化度数数组为0
int i, x, y;
for (i = 1; i < n; i++) // 输入n-1条边
{
scanf("%d%d", &x, &y); // x是y的父亲
father[y] = x; // 记录y的父亲
degree[x]++; // 增加x的度数
}
int count = 0; // p节点的个数
for (i = 1; i <= n; i++) // 遍历每个节点
{
int flag = 1; // 标记是否是p节点
if (father[i]) // 如果存在父亲节点
{
if (degree[i] < degree[father[i]]) // 如果度数小于父亲的度数,不是p节点
flag = 0;
}
int j;
for (j = 1; j <= n; j++) // 遍历所有节点
{
if (father[j] == i && degree[i] < degree[j]) // 如果j是i的子节点,且i的度数小于j的度数,不是p节点
{
flag = 0;
break;
}
}
if (flag) // 如果是p节点,增加计数
count++;
}
printf("%d\n", count); // 输出p节点的个数
}
return 0;
}