第六次CCF-CSP认证(含C++源码)
第六次CCF-CSP认证
- 数位之和(easy)
- 思路及AC代码
- 遇到的问题
- 开心消消乐(easy)
- 思路及AC代码
- 画图(mid)
- 思路及AC代码
数位之和(easy)
题目链接
思路及AC代码
既然题目要求我们输出各位数字之和,那么我们之间把这些个位 十位…上的数拿到不就行了,一开始我还想着写一个函数去搞到这个输入n的每一位,返回一个数组,但是首先我们不知道传进来的数字是个几位数,其次就算知道也挺麻烦的,我后来想了一下,我直接把这个数搞成字符串不就行了吗,这样 这个数就不是一个整型,一个整体,而是刚刚好是我需要的 由若干个数字组成的字符串,ok,代码来咯:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string n;
cin>>n;
int res=0;
for(auto c:n)
{
res+=c-'0';
}
cout<<res<<endl;
return 0;
}
遇到的问题
开心消消乐(easy)
题目链接
思路及AC代码
对于矩阵中的每个元素 s[i][j],使用四个变量 left、right、up 和 under 分别记录该元素向左右上下四个方向扩展的边界位置。
初始化 left 和 right 为当前列 j,up 和 under 为当前行 i。
使用四个 while 循环分别向左右上下四个方向扩展,直到遇到不同的数字或超出矩阵边界为止。
计算横向连续相同数字的长度为 right - left - 1,纵向连续相同数字的长度为 under - up - 1。
如果横向或纵向的连续长度大于等于 3,则将 p[i][j] 标记为 true,表示该位置可以消除;否则标记为 false。
#include <bits/stdc++.h>
using namespace std;
const int N =33;//多开几个
int s[N][N];
bool p[N][N];//状态数组
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>s[i][j];
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
int left=j,right=j,up=i,under=i;
int x=s[i][j];//目前的位置
while(left>=0 && s[i][left]==x) left--;
while(right<m && s[i][right]==x) right++;
while(up>=0 && s[up][j]==x) up--;
while(under<n && s[under][j]==x) under++;
//由某个点向四周扩展
p[i][j]=right-left-1>=3 || under-up-1>=3;
//如果相同数字长度大于等于3则标记为可以消除
//下面是对这行代码的分步骤解释
}
}
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
//解释:
// 计算左右方向相同数字的连续长度
int leftRightLength = right - left - 1;
// 计算上下方向相同数字的连续长度
int upUnderLength = under - up - 1;
// 判断左右或上下方向的连续长度是否大于等于 3
bool canEliminate = leftRightLength >= 3 || upUnderLength >= 3;
// 将判断结果存储到状态数组 p 中
p[i][j] = canEliminate;
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(p[i][j])
{
cout<<0<<' ';
}else{
cout<<s[i][j]<<' ';
}
}
cout<<endl;
}
return 0;
}
画图(mid)
题目链接
思路及AC代码
分析:
给定一个 m * n 的画布,初始画布上每个位置用点来填充 可以把每一个方块理解为一个像素
这题就两种操作(输入):
操作 0(画线):在画布上画线段,水平线段用 - 表示,垂直线段用 | 表示,线段交叉处用 + 表示。
操作 1(染色):从指定位置开始进行填充操作,将该位置及其连通区域(不跨越线段)填充为指定字符。
思路
画线段操作:对于操作 0,输入两个端点坐标,将两点之间的线段绘制在画布上。若线段交叉,交叉处标记为 +。
填充操作:对于操作 1,使用深度优先搜索(DFS)算法从指定位置开始填充,遇到线段则停止填充。(dfs如果有问题就去看一下我之前的文章迷宫问题)
下面这是yxc课上的代码 我用AI生成注释后供大家参考:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int n, m, Q;//Q表示询问次数
char g[N][N]; // 存储图形的二维数组,记录每个位置的字符
bool st[N][N]; // 标记数组,用于深度优先搜索中记录对应位置是否已访问过
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; // 定义上下左右四个方向的坐标偏移量 类似迷宫问题
// 深度优先搜索函数,用于填充颜色
// x, y:当前处理的坐标位置;c:要填充的目标字符
void dfs(int x, int y, char c) {
st[x][y] = true; // 标记当前位置已访问,避免重复处理
g[x][y] = c; // 将当前位置的字符设置为目标填充字符
for (int i = 0; i < 4; i++) { // 遍历四个方向(上、右、下、左)
int a = x + dx[i], b = y + dy[i]; // 计算相邻位置的坐标
// 检查相邻位置是否在图形范围内,且未被访问过
if (a >= 0 && a < m && b >= 0 && b < n && !st[a][b]) {
// 若该位置是线条字符('-'、'|'、'+'),则不进行填充
if (g[a][b] == '-' || g[a][b] == '|' || g[a][b] == '+') continue;
dfs(a, b, c); // 递归处理相邻位置,实现颜色填充
}
}
}
int main() {
cin >> m >> n >> Q; // 输入图形的行数m、列数n,以及操作次数Q
// 初始化图形数组,将所有位置设置为默认字符'.'
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
g[i][j] = '.';
while (Q--) { // 循环处理每一次操作
int op;
cin >> op;
if (op == 0) { // 画矩形操作
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
// 调整坐标,确保x1 <= x2,y1 <= y2
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
// 遍历矩形区域内的所有位置
for (int i = x1; i <= x2; i++) {
for (int j = y1; j <= y2; j++) {
auto &t = g[i][j]; // 取当前位置字符的引用,方便修改
// 处理矩形边界的特殊字符情况(将交叉处设为'+')
if (x1 == x2 && t == '-' || y1 == y2 && t == '|' || t == '+')
t = '+';
else { // 根据矩形是横线还是竖线,设置对应字符
if (x1 == x2) t = '|'; // 竖线矩形
if (y1 == y2) t = '-'; // 横线矩形
}
}
}
} else { // 填充操作(op == 1)
int x, y;
char c;
cin >> x >> y >> c;
memset(st, 0, sizeof st); // 重置访问标记数组
dfs(x, y, c); // 调用深度优先搜索进行颜色填充
}
}
// 输出图形,注意此处进行了坐标转换(行列交换)
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < m; j++)
cout << g[j][i]; // 按转换后的坐标输出字符
cout << endl; // 每行输出结束后换行
}
return 0;
}