PAT甲级刷题记录-(AcWing)-Day17(基础算法 8题)
课程来源AcWing
其中AcWing中的题目为翻译好的中文题目
刷题列表
1091 Acute Stroke
英语单词
解析
使用宽度优先来搜索
得到连通块的数量
注意点
#include <iostream>
#include <queue>
using namespace std;
int edge[60][1286][128];
int m, n, l, t;
struct Node {
int x, y, z;
};
queue<Node> q;
int d[][3] = {
{
0, 0, 1},
{
0, 0, -1},
{
0, 1, 0},
{
0, -1, 0},
{
1, 0, 0},
{
-1, 0, 0},
};
int bfs(int x, int y, int z) {
q.push({
x, y, z});
edge[x][y][z] = 0;
int res = 1;
while (!q.empty()) {
auto node = q.front();
q.pop();
for (int i = 0; i < 6; ++i) {
int a = node.x, b = node.y, c = node.z;
a += d[i][0], b += d[i][1], c += d[i][2];
if (a >= 0 && b >= 0 && c >= 0 && a < l && b < m && c < n && edge[a][b][c]) {
q.push({
a, b, c});
edge[a][b][c] = 0;
res++;
}
}
}
return res;
}
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 >> edge[i][j][k];
}
}
}
int res = 0;
for (int i = 0; i < l; ++i) {
for (int j = 0; j < m; ++j) {
for (int k = 0; k < n; ++k) {
if (edge[i][j][k]) {
int cnt = bfs(i, j, k);
if (cnt >= t) res += cnt;
}
}
}
}
cout << res;
return 0;
}
1148 Werewolf - Simple Version
英语单词
解析
因为N
很小只有100
的数量级, 所以可以枚举, O ( n 3 ) O(n^3) O(n3)
注意点
#include <iostream>
using namespace std;
const int N = 110;
int n;
int sf[N];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i)cin >> sf[i];
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
int liars = 0, wolves = 0;
// 枚举真正的狼人, 此时狼人为 i和j
for (int k = 1; k <= n; ++k) {
//查看有几个人在说谎, 狼人里面有几个在说谎
// printf("i = %d, j = %d k = %d sf = %d\n", i, j, k, sf[k]);
if (sf[k] < 0) {
// k说某个人是狼人
// 判断k有没有说谎
if (sf[k] != -i && sf[k] != -j) {
// k说的人里面没有狼人,他说谎了
// printf("k = %d, sf = %d k is a liar\n", k, sf[k]);
liars++;
// 如果k是狼人,那么增加狼人中说谎的人数
if (k == i || k == j) wolves++;
// printf("liars = %d, wolves = %d\n", liars, wolves);
}
} else {
// k说的对象是好人
if (sf[k] == i || sf[k] == j) {
// k说的好人其实是狼人, k说谎了
// printf("k = %d, sf = %d k is a liar\n", k, sf[k]);
liars++;
if (k == i || k == j) wolves++;
// printf("liars = %d, wolves = %d\n", liars, wolves);
}
}
}
// printf("liars = %d, wolves = %d\n", liars, wolves);
if (liars == 2 && wolves == 1) {
cout << i << " " << j;
return 0;
}
}
}
puts("No Solution");
return 0;
}
1051 Pop Sequence
英语单词
解析
注意点
插入的序列为1
到n
, 使用一个栈s
来模拟push
和pop
的过程
先将元素入栈, 然后检查栈头元素和给定的序列头是否相同,一直相同的话就出队 重复
结束后如果栈为空则序列合法,否则不合法
#include <iostream>
#include <stack>
const int N = 1010;
using namespace std;
int m, n, k;
int seq[N];
bool check() {
stack<int> s;
for (int i = 1, j = 1; i <= n; ++i) {
s.push(i);
if (s.size() > m) return false;
while (!s.empty() && s.top() == seq[j] ) {
s.pop();
j++;
}
}
return s.empty();
}
int main() {
cin >> m >> n >> k;
while (k--) {
for (int i = 1; i <= n; ++i) {
cin >> seq[i];
}
if (check()) puts("YES");
else puts("NO");
}
return 0;
}
1055 The World’s Richest
英语单词
解析
创建一个时间数组,记录每个age的人物链表,分别排序,最后按要求取最大值即可
注意点
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 210;
int n, k, m;
struct Person {
string name;
int age, wealth;
bool operator<(const Person &p) const {
if (wealth != p.wealth) return wealth > p.wealth;
if (age != p.age) return age < p.age;
return name < p.name;
}
};
vector<Person> year[N];
int main() {
cin >> n >> k;
while (n--) {
string name;
int age, wealth;
cin >> name >> age >> wealth;
year[age].push_back({
name, age, wealth});
}
for (auto &item:year) {
sort(item.begin(), item.end());
}
for (int j = 1; j <= k; ++j) {
cin >> m;
int start, end;
cin >> start >> end;
printf("Case #%d:\n", j);
int cnt[N];
memset(cnt, 0, sizeof cnt);
bool suc = false;
while (m--) {
int t = -1;
for (int i = start; i <= end; ++i) {
if (cnt[i] < year[i].size()) {
if (t == -1 || year[i][cnt[i]] < year[t][cnt[t]]) {
t = i;
}
}
}
if (t == -1) break;
auto &p = year[t][cnt[t]];
cnt[t]++;
printf("%s %d %d\n", p.name.c_str(), p.age, p.wealth);
suc = true;
}
if(!suc) puts("None");
}
return 0;
}
!!!1057 Stack
英语单词
解析
用两个堆来模拟
注意点
1117 Eddington Number
英语单词
解析
注意点
这边是超过E, 第一遍写成大于等于E了
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int day[N];
int n;
int main() {
cin >> n;
int res = 0;
for (int i = 1; i <= n; ++i) {
cin >> day[i];
}
sort(day + 1, day + n + 1, greater<int>());
for (int i = n; i >= 1; i--) {
if (day[i] > i) {
cout << i;
return 0;
}
}
puts("0");
return 0;
}
1044 Shopping in Mars
英语单词
解析
因为输出的是1-5
这种形式,所以只要考虑哪个区间的和刚好大于等于m
即可(避免考虑从左边切开链条和从右边切开链条的情况), 所以可以使用前缀和的思想,s[1]
存放从1
的价值,s[2]
存放1-2
的价值,s[n] - s[m]
存放从m + 1 ~ n
的价值
注意点
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int s[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> s[i];
s[i] += s[i - 1]; //前缀和
// s[1] = 1
// s[2] = 1 - 2
// s[n] = 1 - n
// s[n] - s[m] = m + 1 ~ n
}
int res = 0x3f3f3f3f;
for (int i = 1, j = 0; i <= n; ++i) {
// 让j不断变大,找到大于等于m的最小值
// 因为不知道区间里面是否存在刚好等于m的
// 遍历 i~j之间的价值,找到第一个大于等于m的
while (j < n && s[j] - s[i - 1] < m) j++;
// 因为j = n的时候没判断过是否满足
if (s[j] - s[i - 1] >= m) res = min(s[j] - s[i - 1], res);
}
for (int i = 1, j = 0; i <= n; ++i) {
while (j < n && s[j] - s[i - 1] < m) j++;
// 因为j = n的时候没判断过是否满足
if (s[j] - s[i - 1] == res) {
cout << i << "-" << j << endl;
}
}
return 0;
}
1040 Longest Symmetric String
解析
因为字符串在1000以内,所以可以枚举来做
使用双指针,遍历字符串,选取每一个点作为回文串的中心的,依次向两边拓展,记录最大值
枚举的时候要注意
回文串有奇数和偶数两种请客
奇数的中心点为i
,左右指针为i-1
,i+1
偶数的左指针为i
,右指针为i+1
;
所以每个点这两种情况都要枚举到
注意点
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin, s);
int res = 0;
for (int i = 0; i < s.size(); ++i) {
int l = i - 1, r = i + 1;
while (l >= 0 && l < s.size() && r < s.size() && s[l] == s[r]) l--, r++;
res = max(res, r - l - 1);
l = i, r = i + 1;
while (l >= 0 && l < s.size() && r < s.size() && s[l] == s[r]) l--, r++;
res = max(res, r - l - 1);
}
cout << res << endl;
return 0;
}