第十六节 图论 - 1

1|0AT_abc182_d 题解

洛谷链接&Atcoder 链接

本篇题解为此题较简单做法较少码量,并且码风优良,请放心阅读。

2|0题目简述

从数轴的原点开始向正方向走。

第一次向前走 a1 步,第二次向前走 a1+a2,以此类推。

求走过的最大位置

3|0思路

首先直接模拟时间复杂度 O(n2),看一下数据范围 (1N2×105) 得知此方法会超时

那么就需要一点优化,用前缀和即可解决此题,没学过前缀和的建议看这个通过前缀和求出前 i 项的和就很容易解决此题了:

for(int i = 1; i <= n; i ++) { cin >> a[i]; pre[i] = pre[i - 1] + a[i]; }

预处理前缀和,在预处理的过程中同步求最大值,但因为此题的答案即最大值有可能在过程中产生故需要 O(N) 遍历前缀和求最大,此时间复杂度可以接受。

经过以上分析和前缀和优化,很容易即可得出代码了:

#include<iostream> using namespace std; int n, a[200005]; long long pre[200005], maxn[200005]; // 前缀和数组及最大前缀和数组 int main() { cin >> n; for(int i = 1; i <= n; i ++) { cin >> a[i]; pre[i] = pre[i - 1] + a[i]; // 预处理前缀和 maxn[i] = max(maxn[i - 1], pre[i]); // 预处理前缀和最大值 } long long temp, ans = -0x3f3f3f3f; // ans 要求最大值,所以建议赋值一个足够小的负数 for(int i = 1; i <= n; i ++) { ans = max(ans, maxn[i] + temp); // 遍历求最大值 temp += pre[i]; // 一点点模拟 } cout << ans << endl; // 输出,换行好习惯 return 0; }

提交记录

The End!

4|0AT_arc113_c 题解

洛谷链接&Atcoder 链接

本篇题解为此题较简单做法较少码量,并且码风优良,请放心阅读。

5|0题目简述

现在有一个字符串 S,每一次你可以选择一个 i(1i|S|),如果 Si=Si+1Si+2。就可以将 Si+2 设为 Si

最多能操作几次。

6|0思路

本题比较贪心,让我们先来造一个样例解释一下:

abbfioidddssabsaa 最优的方案是:

  • 先操作 4 次变为 abbfioidddsssssss

  • 再操作 7 次变为 abbfioidddddddddd

  • 最后操作 14 次变为 abbbbbbbbbbbbbbbb

这样最大总操作次数25 次。

从这个样例中可以发现贪心思路,要想总操作次数最大化,就需要从后到前去操作,如果从前到后操作那么后面可操作的连续字母就会被覆盖,这样总操作次数就不是最大了。

对于每次操作,最优的是把后面的所有不相同的字母变为一样,这就涉及到一个问题,如果后面有相同字母如何判断?其实不必再从当前位置往后搜,只需要定义一个 num 一维数组用 numi 表示当前位置的后面字母 i 的个数

对于 num 数组需要在搜的过程中处理。如果遇到可以替换的情况就把当前位置后的字母全变为当前字母,同时需清空 num 数组的记录,把当前位置的字母数记录即可。

替换后,ans 需增加 ni,考虑到后面的相同字母,所以就需要用到我们维护num 数组了,所以操作数需减去 numstria

经过以上分析及优化后,很容易即可写出代码了:

#include<iostream> using namespace std; string str; long long ans = 0, num[205]; int main() { cin >> str; int n = str.length(); // 记录 str 的长度 num[str[n - 1] - 'a'] ++, num[str[n - 2] - 'a'] ++; // 初始化 num 数组 for(int i = n - 3; i >= 0; i --) { num[str[i] - 'a'] ++; // 记录此位置的字母 // 满足替换的条件 if(str[i + 1] != str[i + 2] && str[i] == str[i + 1]) { ans += n - i - num[str[i] - 'a']; for(int j = 0; j < 26; j ++) num[j] = 0; // 清空 num 数组 num[str[i] - 'a'] = n - i; // 记录替换后的字母数 } } cout << ans << endl; // 输出,换行好习惯 return 0; }

提交记录

The End!

7|0A. 大回复术

题目描述

北方之大德鲁伊天空之怒释放的大回复术是一等一的神术。大回复术之所以能够有极强的治疗效果,是因为该法术能够以人体经络为基本,并建立至多两条(也可以一条都不建立)用于疏通能量的经络。

人体的经络可以看作一张 n 个点的图,里面有 m 条已经连接好的经络。大回复术能够新建至多两条经络。如果每一个点都有偶数条经络与之相连,则经络中的能量会立刻循环往复生生不息,达到治疗的效果。现在你需要回答的是,对于一个给出的经络图,是否能够通过施展大回复术使得其中的能量生生不息。

输入格式

第一行两个整数 nm,接下来 m 行每行两个整数表示一条已经存在的经络。

输出格式

输出一行,为 true 或者 false

样例输入

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

样例输出

true

添加 4-5 即可。

样例输入

4 2 1 2 3 4

样例输出

true

添加 1-3、2-4 即可。

样例输入

4 3 1 2 1 3 1 4

样例输出

false

数据规模

0n,m105

点击查看代码
#include<iostream> #include<vector> using namespace std; int n, m, num; vector<int> vt[100005]; int main() { cin >> n >> m; if(n == 2 && m) { cout << "false\n"; return 0; } for(int i = 1; i <= m; i ++) { int from, to; cin >> from >> to; vt[from].push_back(to); vt[to].push_back(from); } for(int i = 1; i <= n; i ++) { if(vt[i].size() % 2) num ++; if(vt[i].size() == n - 1 && vt[i].size() % 2) { cout << "false\n"; return 0; } } if(num > 4 || num == n) cout << "false\n"; else cout << "true\n"; return 0; } 编译结果 compiled successfully time: 11ms, memory: 5848kb, score: 100, status: Accepted > test 1: time: 2ms, memory: 5808kb, points: 10, status: Accepted > test 2: time: 0ms, memory: 5748kb, points: 10, status: Accepted > test 3: time: 1ms, memory: 5792kb, points: 10, status: Accepted > test 4: time: 1ms, memory: 5696kb, points: 10, status: Accepted > test 5: time: 2ms, memory: 5732kb, points: 10, status: Accepted > test 6: time: 1ms, memory: 5724kb, points: 10, status: Accepted > test 7: time: 1ms, memory: 5748kb, points: 10, status: Accepted > test 8: time: 1ms, memory: 5724kb, points: 10, status: Accepted > test 9: time: 1ms, memory: 5812kb, points: 10, status: Accepted > test 10: time: 1ms, memory: 5848kb, points: 10, status: Accepted

8|0B. 雪花图

题目描述

一个雪花图是由两个大于 1 的整数 xy 构成的:

从一个中心点开始

x 个点连接着中心点

x 个点中每个点都有y个点与其连接着

下面是当 x=5,y=3 时的一张雪花图:

上图的中心点为 155x 点分别为:(3,6,7,8,20),每个点都有 y=3 个点与其连着.

现在给你一张雪花图,请你确定该图 xy 的值.

输入格式

第一行包含一个正整数 t (1t1000),表示测试数据组数

对于每个测试数据,第一行包含两个整数 nm (2n200;1mmin(1000,n(n1)2)),表示雪花图的点数和边数.

接下来 m 行每行包含两个整数 uv (1u,vn,uv),代表一条边.

数据保证没有重边和自环并且一定是一张雪花图,xy 均大于 1

输出格式

对于每个测试数据,每行空格输出 xy.

样例输入#1

3 21 20 21 20 5 20 13 20 1 3 11 3 10 3 4 8 19 8 14 8 9 7 12 7 17 7 18 6 16 6 2 6 6 15 7 15 8 15 20 15 3 15 7 6 1 2 1 3 2 4 2 5 3 6 3 7 9 8 9 3 3 6 6 2 2 1 5 2 2 7 4 3 3 8

样例输出#1

5 3 2 2 2 3
点击查看代码
#include<iostream> #include<vector> #include<string.h> using namespace std; int T, n, m; vector<int> v[1005]; int main() { cin >> T; while(T --) { int num = 0; cin >> n >> m; for(int i = 1; i <= m; i ++) { int from, to; cin >> from >> to; v[from].push_back(to), v[to].push_back(from); } for(int i = 1; i <= n; i ++) if(v[i].size() == 1) num ++; int x = n - num - 1; int y = num / x; cout << x << " " << y << endl; for(int i = 1; i <= n; i ++) v[i].clear(); } return 0; } 编译结果 compiled successfully time: 21ms, memory: 3512kb, score: 100, status: Accepted > test 1: time: 0ms, memory: 3448kb, points: 10, status: Accepted > test 2: time: 1ms, memory: 3484kb, points: 10, status: Accepted > test 3: time: 0ms, memory: 3448kb, points: 10, status: Accepted > test 4: time: 1ms, memory: 3496kb, points: 10, status: Accepted > test 5: time: 4ms, memory: 3456kb, points: 10, status: Accepted > test 6: time: 1ms, memory: 3492kb, points: 10, status: Accepted > test 7: time: 2ms, memory: 3512kb, points: 10, status: Accepted > test 8: time: 5ms, memory: 3460kb, points: 10, status: Accepted > test 9: time: 5ms, memory: 3440kb, points: 10, status: Accepted > test 10: time: 2ms, memory: 3496kb, points: 10, status: Accepted

9|0C. 那是一棵树吗?

题目描述

树是一种常见的数据结构.

一棵树的根节点只有一个,并且没有其他点指向它.从根节点遍历有向边,我们只会得到唯一的一个序列.

例如,下图中前两个例子是树,第三个不是:



给你 t 张有向图,请你判断每张图是否是一颗树.

输入格式

第一行包含一个正整数 t (1t2000),表示测试数据组数

对于每个测试数据,第一行包含两个整数 nm(2n200000;1m200000),表示图的点数和边数.

接下来 m 行每行包含两个整数 uv(1u,vn,uv),代表一条 u 指向 v 的边.

数据保证没有重边和自环.

对于所有测试数据,数据总量不超过 2×105.

输出格式

对于每个测试数据,输出 Case k is a tree.;如果第 k 个测试数据是一棵树,否则输出 Case k is not a tree.

样例输入#1

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

样例输出#1

Case 1 is a tree. Case 2 is a tree. Case 3 is not a tree.
点击查看代码
#include<iostream> #include<vector> #include<string.h> #include<cmath> #include<bits/stdc++.h> using namespace std; int T, n, m, vis[200005], num = 0; vector<int> v[200005]; void dfs(int x) { vis[x] = true; for(int i = 0; i < v[x].size(); i ++) { if(vis[v[x][i]]) continue; dfs(v[x][i]); } return; } void f(int Case) { bool flag; cin >> n >> m; for(int i = 1; i <= n; i ++) v[i].clear(), vis[i] = false; for(int i = 1; i <= m; i ++) { int from, to; cin >> from >> to; v[from].push_back(to); v[to].push_back(from); } dfs(1); if(count(vis + 1, vis + n + 1, true) == n) flag = true; else flag = false; if(m != n - 1) flag = false; if(flag) printf("Case %d is a tree.\n", Case); else printf("Case %d is not a tree.\n", Case); return; } int main() { cin >> T; for(int j = 1; j <= T; j ++) f(j); return 0; } 编译结果 compiled successfully time: 456ms, memory: 15532kb, score: 100, status: Accepted > test 1: time: 2ms, memory: 8224kb, points: 10, status: Accepted > test 2: time: 46ms, memory: 8280kb, points: 10, status: Accepted > test 3: time: 35ms, memory: 8168kb, points: 10, status: Accepted > test 4: time: 16ms, memory: 8292kb, points: 10, status: Accepted > test 5: time: 37ms, memory: 8272kb, points: 10, status: Accepted > test 6: time: 45ms, memory: 8160kb, points: 10, status: Accepted > test 7: time: 47ms, memory: 8284kb, points: 10, status: Accepted > test 8: time: 47ms, memory: 8048kb, points: 10, status: Accepted > test 9: time: 53ms, memory: 8180kb, points: 10, status: Accepted > test 10: time: 128ms, memory: 15532kb, points: 10, status: Accepted

__EOF__

本文作者So_noSlack
本文链接https://www.cnblogs.com/So-noSlack/p/17585860.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   So_noSlack  阅读(121)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示