第十四次CCF-CSP认证(含C++源码)

第十四次CCF-CSP认证

卖菜

题目链接

满分思路

就是模拟一下这个调整第二天菜价的过程,其中对于两种只有一个邻居的情况下做出调整,三个for循环分别处理
输入,调整,输出

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int yes[N],today[N];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>yes[i];
    }
    for(int i=1;i<=n;i++)
    {
        if(i==1)
        {
            today[i]=(yes[i]+yes[i+1])/2;
        }else if(i==n)
        {
            today[n]=(yes[n-1]+yes[n])/2;
        }else{
            today[i]=(yes[i-1]+yes[i]+yes[i+1])/3;
        }
    }
    for(int i=1;i<=n;i++)
    {
        cout<<today[i]<<" ";
    }
}

买菜


题目链接

满分思路

这题说白了就是两个人都去买菜去了,然后回来把菜装车的时候俩人会聊会天,这样一来一回,问的是 两个人在这个买菜的过程中能聊多久,其实题目已经给出提示了,对于时间段用区间来表示,那么我们是不是只需要找到两个人时间重合的部分就好,对于这个重合部分怎么表示呢
画个图其实就很明了了,这里截一下Y总课上的图示
即:两个区间右端点取一个两者最小值(min)减去左端点取一个最大值

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
const int N=2010;
int n;
PII p[N],q[N];
int get(PII a,PII b)
{
    if(a.y<b.x ||b.y<a.x)
    {
        return 0;
    }else{
        return min(a.y,b.y)-max(a.x,b.x);//对于线段的重合部分取(右端点最小-左端点最大)
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>p[i].x>>p[i].y;
    }
     for(int i=0;i<n;i++)
    {
        cin>>q[i].x>>q[i].y;
    }
    int res=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            res+=get(p[i],q[j]);
        }
    }
    cout<<res<<endl;
    return 0;
}

再卖菜

第三题是个大模拟 非常麻烦 先跳过了 满分比较艰难
这三题名字?? 我还以为我题目看错了 这出题人???

题目链接

满分题解(差分约束)

其实这题你仔细看一下,是不是就是第一道题的逆过程,但是往往逆过程是比较难的,这题就是,
知道今天的菜价,问你的是昨天菜价多少,这个其实就需要我们自己找约束条件了,虽然调整的规则一样
但往往你并不能通过这家或几家今天的菜价就能知道这家昨天的菜价,而且这对于所有店都是这样,这其实就是难点所在 等我学完 差分约束 回来补上个人心得

solution 1(枚举 correct but 超时)

cpp 复制代码
#include <iostream>
#include <vector>

using namespace std;

// 检查当前枚举的第一天菜价序列是否符合第二天菜价的要求
bool check(const vector<int>& day1Prices, const vector<int>& day2Prices) {
    int n = day1Prices.size();
    // 检查第一个商店
    if ((day1Prices[0] + day1Prices[1]) / 2 != day2Prices[0]) {
        return false;
    }
    // 检查中间的商店
    for (int i = 1; i < n - 1; ++i) {
        if ((day1Prices[i - 1] + day1Prices[i] + day1Prices[i + 1]) / 3 != day2Prices[i]) {
            return false;
        }
    }
    // 检查最后一个商店
    if ((day1Prices[n - 2] + day1Prices[n - 1]) / 2 != day2Prices[n - 1]) {
        return false;
    }
    return true;
}

// 枚举并找到符合要求的第一天菜价
vector<int> findDay1Prices(const vector<int>& day2Prices) {
    int n = day2Prices.size();
    vector<int> day1Prices(n);
    // 枚举第一个商店的菜价,从 1 开始
    for (int firstPrice = 1; ; ++firstPrice) {
        day1Prices[0] = firstPrice;
        bool valid = true;
        // 推导后续商店的菜价
        for (int i = 1; i < n; ++i) {
            if (i == 1) {
                // 第二个商店的菜价根据第一个商店和自身推导
                day1Prices[i] = 3 * day2Prices[i - 1] - day1Prices[i - 1];
                if (day1Prices[i] <= 0) {
                    valid = false;
                    break;
                }
            } else if (i == n - 1) {
                // 最后一个商店的菜价根据前一个商店和自身推导
                day1Prices[i] = 2 * day2Prices[i] - day1Prices[i - 1];
                if (day1Prices[i] <= 0) {
                    valid = false;
                    break;
                }
            } else {
                // 中间商店的菜价根据相邻商店推导
                day1Prices[i] = 3 * day2Prices[i] - day1Prices[i - 1] - day1Prices[i - 2];
                if (day1Prices[i] <= 0) {
                    valid = false;
                    break;
                }
            }
        }
        if (valid && check(day1Prices, day2Prices)) {
            return day1Prices;
        }
    }
    return {};
}

int main() {
    int n;
    cin >> n;
    vector<int> day2Prices(n);
    for (int i = 0; i < n; ++i) {
        cin >> day2Prices[i];
    }
    vector<int> day1Prices = findDay1Prices(day2Prices);
    for (int i = 0; i < n; ++i) {
        if (i > 0) {
            cout << " ";
        }
        cout << day1Prices[i];
    }
    cout << endl;
    return 0;
}

solution 2(正解)

作者:Tilbur
代码解析

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 310,M=1e5+10;
int h[N], e[M], w[M], ne[M], idx;
int q[N], dist[N];
bool st[N];
int b[N];
int n;

void add(int a, int b, int c)  // 添加一条边a->b,边权为c
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}


void spfa()  // 求1号点到n号点的最短路距离
{
    int hh = 0, tt = 0;
    memset(dist, -0x3f, sizeof dist);
    dist[0] = 0;
    q[tt ++ ] = 0;


    while (hh != tt)
    {
        int t = q[hh ++ ];
        if (hh == N) hh = 0;
        st[t] = false;

        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] <dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入
                {
                    q[tt ++ ] = j;
                    if (tt == N) tt = 0;
                    st[j] = true;
                }
            }
        }
    }
}


int main()
{
    scanf("%d", &n);

    for (int i = 1; i <= n; i ++ ) scanf("%d",&b[i]);
    memset(h, -1, sizeof h);

    for(int i=2;i<n;i++){
        add(i-2,i+1,3*b[i]);
        add(i+1,i-2,-3*b[i]-2);
    }

    add(0,2,2*b[1]),add(2,0,-2*b[1]-1);
    add(n-2,n,2*b[n]),add(n,n-2,-2*b[n]-1);

    for(int i=1;i<=n;i++) add(i-1,i,1);

    spfa();
    for(int i=1;i<=n;i++) cout<<dist[i]-dist[i-1]<<' ';

    return 0;
}
相关推荐
@小张要努力36 分钟前
基于STC89C52的8255并行口拓展实验
数据库·单片机·嵌入式硬件·学习·mongodb·51单片机·proteus
CS创新实验室1 小时前
数据结构:队列应用举例——报数问题
数据结构·计算机考研·408考研
froxy1 小时前
C++11 引入了的新特性与实例说明
开发语言·c++
珊瑚里的鱼1 小时前
第一讲 | 解锁C++编程能力:基础语法解析
开发语言·c++·笔记·visualstudio·学习方法·visual studio
程序员yt1 小时前
211 本硕研三,已拿 C++ 桌面应用研发 offer,计划转音视频或嵌入式如何规划学习路线?
c++·学习·音视频
goTsHgo1 小时前
完整的类在JVM中的生命周期详解
java·开发语言·算法
LuckyLay2 小时前
LeetCode算法题(Go语言实现)_08
算法·leetcode·职场和发展·golang
一只_程序媛2 小时前
【leetcode hot 100 78】子集
算法·leetcode·职场和发展
qq_386322692 小时前
华为网路设备学习-16 虚拟路由器冗余协议(VRRP)
学习·华为·智能路由器
沧海一笑-dj2 小时前
【鸿蒙开发】Hi3861学习笔记- WIFI应用AP建立网络
笔记·学习·harmonyos