CCF-CSP 201512 总结

第一题

int main() 
{
    string s;
    int res = 0;
    cin >> s;
    for (int i = 0; i < s.size(); i++) {
        res += s[i] - '0';
    }
    cout << res;
}

第二题

#define N 40
int mp[N][N], res[N][N];
int n, m;

void yx(int i, int j) {
    int cnt = 1;
    //右边
    while ( j + cnt <= m && mp[i][j + cnt] == mp[i][j])    cnt++;
    if (cnt >= 3)
    {
        for (int k = 0; k < cnt; k++) 
        {
            res[i][j + k] = 0;
        }
    }

    cnt = 0;
    while ( i + cnt <= n && mp[i + cnt][j] == mp[i][j])    cnt++;
    if (cnt >= 3) 
    {
        for (int k = 0; k < cnt; k++)
        {
            res[i + k][j] = 0;
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) 
    {
        for (int j = 1; j <= m; j++)
        {
            scanf("%d", &mp[i][j]);
            res[i][j] = mp[i][j];
        }
    }

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            yx(i, j);
    //for (int i = 1; i <= m; i++)
    //    for (int j = 1; j <= n - 2; j++)
    //        xb(mp[i][j]);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++)
            printf("%d ", res[i][j]);
        printf("\n");
    }
}

第三题

memset函数有 头文件cstring, 不写会 编译错误而且没提示
memset 只能填充 -1 或 0;
#include <cstring>
memset( a, 0, sizeof(a) );

90分代码,没找到错误原因:

(2023-3-2更新,找到原因了,在遇到'+'时也要输出'+', 修改后为100分)

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>

using namespace std;
#define N 110
int n, m, q, dx[] = { -1, 0, 1, 0 }, dy[] = {0, 1, 0, -1};
char mp[N][N];
int visited[110][110];

//判断位置(a,b)是否是合法填充位置
bool validpos(int a, int b) {
    if (a < 0 || a >= n || b < 0 || b >= m)
        return false;
    else if (mp[a][b] == '|' || mp[a][b] == '-' || mp[a][b] == '+')
        return false;
    else
        return true;
}

//以(x,y)为中心出发的填充函数(递归)
void fill_the_blank(int x, int y, char c) {
    visited[x][y] = 1;
    for (int i = 0; i < 4; i++) {
        int a = x + dx[i], b = y + dy[i];
        if (validpos(a, b)) {
            mp[a][b] = c;
            if(!visited[a][b])
                fill_the_blank(a, b, c);
        }
    }
}

int main() 
{
    scanf("%d%d%d", &m, &n, &q);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            mp[i][j] = '.';
        }
    }
    for (int i = 0; i < q; i++) {
        int ord;
        scanf("%d", &ord);
        //如果是划线指令0
        if (ord == 0)
        {
            int x1, x2, y1, y2;
            scanf("%d%d%d%d", &y1, &x1, &y2, &x2);
            if (x1 == x2)
            {
                for (int j = min(y1, y2); j <= max(y1, y2); j++) {
                    if(mp[x1][j] == '|' || mp[x1][j] == '+') //最后10分更新内容
                        mp[x1][j] = '+';
                    else
                        mp[x1][j] = '-';
                }
            }
            if (y1 == y2)
            {
                for (int j = min(x1, x2); j <= max(x1, x2); j++) {
                    if(mp[j][y1] == '-' || mp[j][y1] == '+')//最后10分更新内容
                        mp[j][y1] = '+';
                    else
                        mp[j][y1] = '|';
                }
            }
        }
        //如果是填充指令1
        if(ord == 1)
        {
            int x, y;
            char c;
            scanf("%d%d %c", &y, &x, &c);
            memset(visited, 0, sizeof(visited));
            visited[x][y] = 1;
            fill_the_blank(x, y, c);
        }

    }
    for (int i = n - 1; i >= 0; i--) 
    {
        for (int j = 0; j < m; j++)
        {
            printf("%c", mp[i][j]);
        }
        printf("\n");
    }

}

第四题

知识点:欧拉路径
一、无向图:
是否有 欧拉路径
如果度为奇数的点有0个或2个,则存在欧拉路径;
当度为奇数的点有2个时,欧拉路径以这两个点为起点和终点;
是否有 欧拉回路
如果所有点的的度数都为偶数,则存在欧拉回路;
二、有向图:
是否存在 欧拉路径
如果①“所有点入度=出度”,或者“存在一个点的入度=出度+1,一个点的入度=出度-1”,则存在欧拉路径;
是否存在 欧拉回路
所有点的入度=出度,则存在欧拉回路;

知识点:并查集(复习一遍)
p[N]:
①定义一个数组p[N],用p[i]表示 “ i 号结点处在以 p[i] 号结点为根的集合中”;
②初始时“ p[i] = i ”
find(x):
①find(x) 返回的值是x的根节点p[x];
②如果p[x] 中暂时是当前集合的叶子结点,find(x) 会顺带将x结点连到当前集合的根节点;
合并操作:
如果x,y不在同一个集合,则将“x所在集合的 ”并入“y集合”
p[find(x)] = find(y);

注:由于这种并查集自带优化高度功能,所以效率是很高的;
const int N = 100;
int p[N];
//找到集合的根
find(int x){
    //如果不是根节点,则找到其根结点并返回,这个过程中会顺便优化并查集的结构(高度)
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
//判断x,y是否在同一个集合
if(find(x) == find(y))

//如果x,y不在同一个集合,则将“x所在集合的根”并入“y集合”
if(find(x) != find(y)){
    p[find(x)] = find(y);
}
知识点图的set存储的邻接表;
定义一个邻接表:
set<int> h[N];
加边操作:
set[a].insert(b), set[b].insert(a);
set型邻接表从k结点开始的遍历:
for(auto it = h[k].begin() ; it != h[k].end() ; it ++);

具体代码:

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>

using namespace std;

const int N = 10010, M = 100010;
set<int> h[N];
int n, m, p[N], res[M], top;

int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void dfs(int a) {
    //每次删一条双向路径,注意while条件一定要用size(),因为在其他递归也可能删除a的临边
    while (h[a].size()) {
        int b = *h[a].begin();
        h[a].erase(b), h[b].erase(a);
        dfs(b);
    }
    //回溯时记录路径,不能进入时记录(答案好像一样但是不能AC,不知道为什么)
    res[++top] = a;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) p[i] = i;
    for (int i = 0; i < m; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        h[x].insert(y), h[y].insert(x);
        p[find(x)] = find(y);
    }
    int cnt = 0;
    //如果不满足欧拉路径条件则直接打印“-1”并退出
    for (int i = 1; i <= n; i++) {
        if (find(i) != find(1)) {
            cout << -1;
            return 0;
        }
        if (h[i].size() % 2)
            cnt++;
    }
    if (cnt != 0 && cnt != 2 || cnt == 2 && h[1].size() % 2 == 0) {
        cout << -1;
        return 0;
    }
    //满足欧拉条件则从1出发必有欧拉路径,进行dfs
    dfs(1);
    for (int i = top; i; i--) {
        printf("%d ", res[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值