1.1版本 1.代码优化 2.UI优化 videplayer.h #ifndef VIDEPLAYER_H #define VIDEPLAYER_H #include <QMainWindow> #include <QMediaPlayer> #include <QVideoWidget> #include <QSlider> #include <QAudioOutput> #include <QFileDialog> QT_BEGIN_NAMESPACE namespace Ui { class VidePlayer; } QT_END_NAMESPACE class VidePlayer : public QMainWindow { Q_OBJECT public: explicit VidePlayer(QWidget *parent = nullptr); ~VidePlayer() override; private slots: void openfile(); void positionChanged(qint64 pos); void durationChanged(qint64 duration); private: Ui::VidePlayer *ui; QMediaPlayer* player; QAudioOutput* audioOutput; QVideoWidget* videoWidget; bool isSliderPressed; qint64 duration; }; #endif // VIDEPLAYER_H videplayer.cpp #include "videplayer.h" #include "ui_videplayer.h" #include <QDebug> #include <QFile> VidePlayer::VidePlayer(QWidget *parent) : QMainWindow(parent), ui(new Ui::VidePlayer), isSliderPressed(false) { ui->setupUi(this); // 创建播放器对象 player = new QMediaPlayer(this); // 音频输出 audioOutput = new QAudioOutput(this); player->setAudioOutput(audioOutput); // 视频窗口 videoWidget = new QVideoWidget(this); // UI 的 widget_video 创建一个布局 QVBoxLayout* layout = new QVBoxLayout(ui->widget_video); layout->setContentsMargins(0,0,0,0); // 布局中添加视频窗口 layout->addWidget(videoWidget); // 设置视频输出 player->setVideoOutput(videoWidget); // 设置默认音量滑动条 // 音量实际设置的是 当前值/最大值 * 当前系统音量大小 ui->horizontalSlider_volume->setValue(99); connect(ui->horizontalSlider_volume, &QSlider::valueChanged, this, [=](int value) { // audioOutput->setVolume(value / 100.0 ); qreal linearVolume = // 线性 <-> 对数 QAudio::convertVolume( value / qreal(100.0), QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale ); audioOutput->setVolume(linearVolume); }); ui->pushButton_add->setIcon(QIcon(".\\icons\\add.png")); ui->pushButton_play->setIcon(QIcon(".\\icons\\play.png")); ui->pushButton_pause->setIcon(QIcon(".\\icons\\pause.png")); ui->pushButton_stop->setIcon(QIcon(".\\icons\\stop.png")); ui->pushButton_sound->setIcon(QIcon(".\\icons\\vol.png")); connect(ui->pushButton_add, &QPushButton::clicked, this, &VidePlayer::openfile); connect(ui->pushButton_play, &QPushButton::clicked, player, &QMediaPlayer::play); connect(ui->pushButton_pause, &QPushButton::clicked, player, &QMediaPlayer::pause); connect(ui->pushButton_stop, &QPushButton::clicked, player, &QMediaPlayer::stop); // 播放器播放位置 映射到 滑动条位置 connect(player, &QMediaPlayer::positionChanged, this, &VidePlayer::positionChanged); // 打开新文件, 视频总时长 映射到 进度条最大值 connect(player, &QMediaPlayer::durationChanged, this, &VidePlayer::durationChanged); // 用户按下 slider connect(ui->horizontalSlider_pos, &QSlider::sliderPressed, this, [=]() { isSliderPressed = true; }); // 用户释放 slider,滑动条新位置 映射到 播放器播放位置 connect(ui->horizontalSlider_pos, &QSlider::sliderReleased, this, [=]() { isSliderPressed = false; player->setPosition( ui->horizontalSlider_pos->value() * 1000 ); }); // 播放失败 connect(player, &QMediaPlayer::errorOccurred, this, [=](QMediaPlayer::Error error, const QString &errorString) { qDebug() << error << errorString; }); } VidePlayer::~VidePlayer() { delete ui; } void VidePlayer::openfile() { QString fileName = QFileDialog::getOpenFileName(this, "选择视频", "", "Video Files (*.mp4 *.avi *.mkv)"); if(fileName.isEmpty()) return; player->setSource(QUrl::fromLocalFile(fileName)); player->play(); QFileInfo fileInfo(fileName); QString name = fileInfo.completeBaseName(); //ui->label_cur_media->setText(name); setWindowTitle(name); } void VidePlayer::positionChanged(qint64 pos) { // 用户正在拖动时 // 不自动更新 slider if(isSliderPressed) return; ui->horizontalSlider_pos->setValue(pos / 1000); int sec = pos / 1000; int min = sec / 60; int hour = min / 60; sec = sec % 60; int s = duration / 1000; int m = s / 60; int h = m / 60; s = s % 60; ui->label_pos->setText( QString("%1:%2:%3/%4:%5:%6") .arg(hour, 2, 10, QChar('0')) .arg(min, 2, 10, QChar('0')) .arg(sec, 2, 10, QChar('0')) .arg(h, 2, 10, QChar('0')) .arg(m, 2, 10, QChar('0')) .arg(s, 2, 10, QChar('0')) ); } void VidePlayer::durationChanged(qint64 duration) { ui->horizontalSlider_pos->setRange(0, duration / 1000); this->duration = duration; }
QT Media Player V1
最终效果 videplayer.h #ifndef VIDEPLAYER_H #define VIDEPLAYER_H #include <QMainWindow> #include <QMediaPlayer> #include <QVideoWidget> #include <QSlider> #include <QAudioOutput> #include <QFileDialog> QT_BEGIN_NAMESPACE namespace Ui { class VidePlayer; } QT_END_NAMESPACE class VidePlayer : public QMainWindow { Q_OBJECT public: explicit VidePlayer(QWidget *parent = nullptr); ~VidePlayer() override; private slots: void openfile(); // void playPause(); // void playStop(); void positionChanged(qint64 pos); void durationChanged(qint64 duration); // void setPostion(int postion); private: Ui::VidePlayer *ui; QMediaPlayer* player; QAudioOutput* audioOutput; QVideoWidget* videoWidget; bool isSliderPressed; bool isPlaying; }; #endif // VIDEPLAYER_H videplayer.cpp #include "videplayer.h" #include "ui_videplayer.h" #include <QDebug> #include <QFile> VidePlayer::VidePlayer(QWidget *parent) : QMainWindow(parent), ui(new Ui::VidePlayer), isPlaying(false), isSliderPressed(false) { ui->setupUi(this); // 创建播放器对象 player = new QMediaPlayer(this); // 音频输出 audioOutput = new QAudioOutput(this); player->setAudioOutput(audioOutput); // 视频窗口 videoWidget = new QVideoWidget(this); // 放入 UI 的 widget_video 中 QVBoxLayout* layout = new QVBoxLayout(ui->widget_video); layout->setContentsMargins(0,0,0,0); layout->addWidget(videoWidget); // 设置视频输出 player->setVideoOutput(videoWidget); // 默认音量 // audioOutput->setVolume(0.5); ui->horizontalSlider_volume->setValue(50); connect(ui->horizontalSlider_volume, &QSlider::valueChanged, this, [=](int value) { audioOutput->setVolume( value / 100.0 ); }); ui->pushButton_add->setIcon(QIcon(".\\icons\\add.png")); ui->pushButton_play->setIcon(QIcon(".\\icons\\play.png")); ui->pushButton_pause->setIcon(QIcon(".\\icons\\pause.png")); ui->pushButton_stop->setIcon(QIcon(".\\icons\\stop.png")); ui->pushButton_sound->setIcon(QIcon(".\\icons\\vol.png")); connect(ui->pushButton_add, &QPushButton::clicked, this, &VidePlayer::openfile); connect(ui->pushButton_play, &QPushButton::clicked, player, &QMediaPlayer::play); connect(ui->pushButton_pause, &QPushButton::clicked, player, &QMediaPlayer::pause); connect(ui->pushButton_stop, &QPushButton::clicked, player, &QMediaPlayer::stop); // connect(player, &QMediaPlayer::positionChanged, this, &VidePlayer::positionChanged); // connect(ui->horizontalSlider_pos, &QSlider::sliderMoved, this, &VidePlayer::setPostion); // 播放位置变化 connect(player, &QMediaPlayer::positionChanged, this, &VidePlayer::positionChanged); // 视频总时长变化 connect(player, &QMediaPlayer::durationChanged, this, &VidePlayer::durationChanged); // 用户按下 slider connect(ui->horizontalSlider_pos, &QSlider::sliderPressed, this, [=]() { isSliderPressed = true; }); // 用户释放 slider connect(ui->horizontalSlider_pos, &QSlider::sliderReleased, this, [=]() { isSliderPressed = false; player->setPosition( ui->horizontalSlider_pos->value() * 1000 ); }); // 播放失败 connect(player, &QMediaPlayer::errorOccurred, this, [=](QMediaPlayer::Error error, const QString &errorString) { qDebug() << error << errorString; }); } VidePlayer::~VidePlayer() { delete ui; } void VidePlayer::openfile() { QString fileName = QFileDialog::getOpenFileName(this, "选择视频", "", "Video Files (*.mp4 *.avi *.mkv)"); if(fileName.isEmpty()) return; player->setSource(QUrl::fromLocalFile(fileName)); player->play(); QFileInfo fileInfo(fileName); QString name = fileInfo.completeBaseName(); ui->label_cur_media->setText(name); isPlaying = true; } // void VidePlayer::playPause() // { // if(isPlaying) // { // player->pause(); // } // else // { // player->play(); // } // isPlaying = !isPlaying; // } // void VidePlayer::playStop() // { // player->stop(); // } void VidePlayer::positionChanged(qint64 pos) { // 用户正在拖动时 // 不自动更新 slider if(isSliderPressed) return; ui->horizontalSlider_pos->setValue(pos / 1000); int sec = pos / 1000; int min = sec / 60; sec = sec % 60; ui->label_pos->setText( QString("%1:%2") .arg(min, 2, 10, QChar('0')) .arg(sec, 2, 10, QChar('0')) ); } void VidePlayer::durationChanged(qint64 duration) { ui->horizontalSlider_pos->setRange(0, duration / 1000); } // void VidePlayer::setPostion(int postion) // { // player->setPosition(postion); // }
Linux内核编译
环境:Ubuntu 6.14.0-37-generic 拉取linux内核源码: git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 环境依赖安装: apt install -y build-essential bc bison flex libssl-dev libelf-dev dwarves ncurses-dev fakeroot cpio rsync kmod gawk git python3 perl 配置文件.config linux内核编译前,需要进行make menuconfig,图形化设置系统配置或裁剪 但最终都是要生成.config 文件,LiteOS也是如此。 笔者直接使用当前系统的.config, 同时关闭ubuntu官方内核的系统证书 cp /boot/config-6.14.0-37-generic .config scripts/config --disable SYSTEM_TRUSTED_KEYS scripts/config --disable SYSTEM_REVOCATION_KEYS 新内核会有许多新选项,使用olddefconfig自动使用默认值 make olddefconfig 多核编译: make -j$(nproc) 最终: ls arch/x86/boot/bzImage // 新内核镜像 make kernelrelease // 查看内核版本 即表示内核编译成功, 后续继续更有价值的事情: 1. 源码结构 kernel/ — 核心调度 mm/ — 内存管理 fs/ — 文件系统 net/ — 网络 drivers/ — 驱动 arch/x86/ — x86架构 init/ — 启动 ipc/ — 进程通信 2. 加printk 如 printk(KERN_INFO "hello kernel\n"); 重新编译,学习内核 ...
OD Machine Test2
// 一组非负整数的数据,0元素会把数据分段,然后最多有k次机会, // 每次可以把一段的数据每一个值都减一。 // 问,这k次机会使用完之后,这组数据的最小和 struct Solution41 { vector<vector<int>> res; void fenduan(vector<int>& arr, int s, int e) { for(int i = s; i <= e; ++i) { vector<int> seg(2, 0); if(arr[i] == 0) continue; // 遇到0跳过 seg[0] = i; // 连续非0段的第一个下标 int j = i; while(j <= e && arr[j] != 0) j++; // 寻找连续非0段的最后一个下标 if(j == e) { // 直到最后一个也不为0 seg[1] = j; } else { seg[1] = j - 1; } res.push_back(seg); i = j; } } int arrSum(vector<int>& arr) { int sum = 0; for(auto it : arr) sum+=it; return sum; } int fun(vector<int>& arr, int k) { int sum = arrSum(arr); int n = arr.size(); fenduan(arr, 0, n-1); int cnt = 1; while(cnt <= k) { int n = res.size(); int maxlen = 0, idx = 0; for(int i = 0; i < n; ++i) { if(maxlen <= res[i][1] - res[i][0] + 1) { maxlen = res[i][1] - res[i][0] + 1; idx = i; } } int minv = INT_MAX; int l = res[idx][0], r = res[idx][1]; for(int i = l; i <= r; ++i) { minv = min(minv, arr[i]); } for(int i = l; i <= r; ++i) { arr[i] -= minv; } res.erase(idx); fenduan(arr, l, r); if(cnt + minv <= k){ sum -= maxlen*minv; cnt = cnt + minv + 1; } else { minv = k - cnt; sum -= maxlen*minv; break; } } } };
Opencv DNN FaceRecognize +QT
最终效果 test.h #ifndef TEST_H #define TEST_H #include <QWidget> #include <QTimer> #include <opencv2/opencv.hpp> #include <opencv2/dnn.hpp> QT_BEGIN_NAMESPACE namespace Ui { class test; } QT_END_NAMESPACE class test : public QWidget { Q_OBJECT public: explicit test(QWidget *parent = nullptr); ~test() override; private slots: void on_ptn_start_clicked(); void readFrame(); void on_ptn_record_clicked(); private: Ui::test *ui; cv::VideoCapture cap; QTimer *timer; cv::CascadeClassifier faceCascade; // 增加分类器对象,用于加载模型 cv::dnn::Net faceDetector; cv::dnn::Net faceRecognizer; std::map<QString, cv::Mat> faceDatabase; cv::Mat lastFeature; void loadDatabase(); void saveDatabase(); QString recognizeFace(cv::Mat feature); // 增加录入人脸功能 bool recording = false; QString recordName; int recordCount = 0; const int maxSamples = 30; void testopencv(); }; #endif // TEST_H test.cpp #include "test.h" #include "ui_test.h" #include <QImage> #include <QPixmap> #include <opencv2/opencv.hpp> test::test(QWidget *parent) : QWidget(parent) , ui(new Ui::test) { ui->setupUi(this); timer = new QTimer(this); // readFrame通过定时器时间循环来触发 // 如果通过while(1)循环,UI会卡死 connect(timer, &QTimer::timeout, this, &test::readFrame); // 使用分类器加载opencv自带的模型 if(!faceCascade.load("haarcascade_frontalface_default.xml")) { qDebug()<<"face cascade load failed"; } // 加载人脸检测模型,SSD CNN检测器 faceDetector = cv::dnn::readNetFromCaffe("models/deploy.prototxt", "models/res10_300x300_ssd_iter_140000.caffemodel"); // 人脸特征模型:128维人脸特征 faceRecognizer = cv::dnn::readNetFromTorch("models/nn4.small2.v1.t7"); loadDatabase(); } test::~test() { delete ui; } void test::on_ptn_start_clicked() { //testopencv(); cap.open(0); // 0 = 默认摄像头 if(!cap.isOpened()) { qDebug()<<"camera open failed"; return; } timer->start(30); // 30ms ≈ 33fps } void test::readFrame() { cv::Mat frame; cv::Mat gray; cap >> frame; if(frame.empty()) return; #if 0 std::vector<cv::Rect> faces; cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY); // OpenCV 默认BGR, 而QT是RGB // cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB); // scaleFactor含义: 图像缩放比例。原理: 模型训练时的窗口大小是固定的(比如 24*24), // 为了检测图像中不同大小的人脸,算法会不断缩放原图。 // 影响: * 1.1 表示每次缩放时图像缩小 10%。 // 值越小(如 1.05): 缩放层级越密,检测更精细,不容易漏掉小脸,但计算量剧增,速度变慢。 // 值越大(如 1.4): 缩放速度快,检测速度快,但可能会跳过某些尺寸的人脸,导致漏检。 // minNeighbors含义: 最小相邻矩形个数。 // 原理: 滑动窗口在检测时,同一个目标附近可能会产生多个重叠的检测框。 // 该参数规定:只有当一个目标被至少 3 个重叠框同时检测到时,才会被最终判定为“人脸”。 // 影响:值越高: 准确度越高,能有效过滤噪声和误报(False Positives),但可能导致难以识别光线不好的人脸。 // 值越低(如 0 或 1): 极其灵敏,但会有大量错误识别(把背景里的阴影看成人脸)。 // minSize含义: 目标的最小尺寸。说明: 低于这个尺寸(比如 30*30)的对象会被忽略。 // 如果你是在近距离摄像头前,可以调大这个值以提高速度;如果你需要检测远处的人脸,则需要调小它。 faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, cv::Size(30,30)); // 画面中识别到多张脸,都画出来 for(auto &face : faces) { cv::rectangle(frame, face, cv::Scalar(0,255,0), 2); } cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB); QImage img(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888); ui->label_camera->setPixmap(QPixmap::fromImage(img)); #else // 人脸检测 cv::Mat blob = cv::dnn::blobFromImage(frame, 1.0, cv::Size(300,300), cv::Scalar(104,177,123)); faceDetector.setInput(blob); cv::Mat detections = faceDetector.forward(); // 解析检测结果 cv::Mat detMat( detections.size[2], detections.size[3], CV_32F, detections.ptr<float>()); for(int i=0;i<detMat.rows;i++) { float confidence = detMat.at<float>(i,2); if(confidence < 0.6) continue; int x1 = detMat.at<float>(i,3)*frame.cols; int y1 = detMat.at<float>(i,4)*frame.rows; int x2 = detMat.at<float>(i,5)*frame.cols; int y2 = detMat.at<float>(i,6)*frame.rows; cv::Rect faceRect(x1,y1,x2-x1,y2-y1); cv::rectangle(frame,faceRect, cv::Scalar(0,255,0),2); // 裁剪人脸 cv::Mat face = frame(faceRect); // 生成输入 cv::Mat faceBlob = cv::dnn::blobFromImage( face, 1.0/255, cv::Size(96,96), cv::Scalar(), true, false ); // 送入网络 faceRecognizer.setInput(faceBlob); cv::Mat feature = faceRecognizer.forward(); lastFeature = feature.clone(); QString name = recognizeFace(feature); cv::putText(frame, name.toStdString(), cv::Point(x1,y1-10), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0,255,0), 2); } cv::cvtColor(frame,frame, cv::COLOR_BGR2RGB); QImage img(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888); ui->label_camera->setPixmap( QPixmap::fromImage(img) .scaled(ui->label_camera->size(), Qt::KeepAspectRatio) ); #endif } void test::on_ptn_record_clicked() { QString name = ui->lineEdit_name->text(); if(lastFeature.empty()) { qDebug()<<"no face feature"; return; } if(name.isEmpty()) { qDebug()<<"name empty"; return; } faceDatabase[name] = lastFeature; saveDatabase(); } void test::loadDatabase() { cv::FileStorage fs("database/faces.yml", cv::FileStorage::READ); if(!fs.isOpened()) { qDebug() << "database not exist"; return; } for(auto it = fs.root().begin(); it != fs.root().end(); ++it) { cv::Mat feature; (*it) >> feature; faceDatabase[ QString::fromStdString((*it).name()) ] = feature; } fs.release(); } void test::saveDatabase() { cv::FileStorage fs("database/faces.yml", cv::FileStorage::WRITE); if(!fs.isOpened()) { qDebug() << "database open error"; return; } for(auto &item : faceDatabase) { fs << item.first.toStdString() << item.second; } fs.release(); } QString test::recognizeFace(cv::Mat feature) { double minDist = 999; QString name = "Unknown"; for(auto &item : faceDatabase) { double dist = cv::norm(feature,item.second); if(dist < minDist) { minDist = dist; name = item.first; } } if(minDist < 0.6) return name; return "Unknown"; } void test::testopencv() { cv::Mat img = cv::imread("test.jpg"); if(img.empty()) qDebug()<<"opencv load fail"; else cv::imshow("test", img); }
C++ Vscode Env Windows
Windows 平台下 VS Code 配置 C++ 环境与 UTF-8 全链路指南 本文介绍如何在 Windows 平台上,利用 VS Code 搭建高效的 C++ 开发环境,并彻底解决中文乱码问题。 一. 环境准备:安装 MinGW-w64 编译器 VS Code 本身是一个轻量级编辑器,需要外接编译器才能运行 C++。 PS: 网速问题可能需要关闭VPN 下载 MSYS2:前往 msys2.org 下载安装包。 安装工具链:安装完成后,打开 MSYS2 UCRT64 终端,输入以下命令安装完整环境: pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain 二. 配置系统环境变量 bin文件夹(默认C:\msys64\ucrt64\bin)添加到PATH中 CMD窗口验证: g++ –version 三. 配置全链路UTF-8 在 VS Code 中按下 Ctrl + Shift + P。 输入并打开 “首选项: 打开用户设置 (JSON)” (Open User Settings (JSON))。 在 JSON 中加入以下配置: { "terminal.integrated.profiles.windows": { "PowerShell": { "source": "PowerShell", "args": ["-NoExit", "-Command", "chcp 65001"] } }, "terminal.integrated.defaultProfile.windows": "PowerShell" } PS:注意终端重启
CPP Video Player Decode Pattern
CPP Code Demo1: video player play decode #include <iostream> using namespace std; // 纯虚类及其子类 共同服务于第三类(此类是业务应用层概念, 前者是底层逻辑概念)(类似简单工厂) struct IDecode { virtual bool Decode(const char* data, size_t size) = 0; virtual ~IDecode() {} }; struct MP4Decode : public IDecode { bool Decode(const char* data, size_t size) { //todo return true; } ~MP4Decode() {} }; struct AVIDecode : public IDecode { bool Decode(const char* data, size_t size) { //todo return true; } ~AVIDecode() {} }; struct Player { Player(IDecode* de) : decode(de) {} ~Player() {} bool Play(const char* data, size_t size) { if (decode->Decode(data, size)) { cout << "Decode Success, Start Play..." << endl; // to play } else { cout << "Decode Failed, Stop Play..." << endl; } } private: IDecode* decode; };
OD Machine Test Question1
#include <iostream> #include <string> #include <cmath> #include <unordered_map> #include <queue> #include <vector> #include <algorithm> #include <map> #include <set> #include <unordered_set> using namespace std; // 打印机队列 void demo1() { struct Event { int prio; int index; struct CmpBigHeap { bool operator() (const Event& a, const Event& b) { if(a.prio != b.prio) return a.prio < b.prio; return a.index > b.index; } }; }; priority_queue<Event, vector<Event>, Event::CmpBigHeap> pq[5]; int N; cin >> N; int inIndex = 0; for(int i = 0; i < N; ++i) { string s; int printer, prio; cin >> s >> printer; printer--; if(s == "IN") { cin >> prio; inIndex++; Event t = {prio, inIndex}; pq[printer].push(t); } else if (s == "OUT") { if(pq[printer].empty()) cout << "NULL" << endl; else { cout << pq[printer].top().index << endl; pq[printer].pop(); } } } } // 机器人活动区域 int demo2_dfs(vector<vector<int> >& grid, vector<vector<bool> >& visited, int x, int y) { int count = 1; int m = grid.size(); // 总行 int n = grid[0].size(); // 总列 visited[x][y] = true; const int dx[] = {1, -1, 0, 0}; const int dy[] = {0, 0, 1, -1}; for(int i = 0; i < 4; ++i) { int newX = x + dx[i]; int newY = y + dy[i]; if(newX < 0 || newX >= m || newY < 0 || newY >= n) { continue; } if( abs(grid[x][y] - grid[newX][newY]) > 1) { continue; } if(visited[newX][newY]) { continue; } count += demo2_dfs(grid, visited, newX, newY); } return count; } void demo2() { int m, n, k; cin >> m >> n; vector<vector<int> > grid(m, vector<int>(n, 0)); vector<vector<bool> > visited(m, vector<bool>(n, false)); for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { cin >> grid[i][j]; } } int count = 1; for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { if(visited[i][j] == false) { int ret = demo2_dfs(grid, visited, i, j); count = max(count, ret); } } } cout << count << endl; } // 敏感字段加密 void demo3() { int k; cin >> k; string s; cin >> s; vector<string> cmdWords; int i = 0; int n = s.size(); while(i < n) { if(s[i] == '_') { i++; continue; } else if(s[i] == '"') { int j = i+1; while( j < n && s[j] != '"') j++; cmdWords.emplace_back(s.substr(i, j-i+1)); i = j+1; } else { int j = i+1; while(j < n && s[j] != '_') j++; cmdWords.emplace_back(s.substr(i, j-i)); i = j; } } if(k >= cmdWords.size()) { cout << "ERROR" << endl; return; } cmdWords[k] = "******"; for(int i = 0; i < cmdWords.size(); ++i) { if(i) cout << "_"; cout << cmdWords[i]; } } // 数组连续和 void demo4() { int N, x; cin >> N >> x; vector<int> arr(N); for(int i = 0; i < N; ++i) { cin >> arr[i]; } int sumWin = 0; vector<vector<int> > res; // 结果集 int left= 0, right=0; // 窗口边界 int count = 0; for( ; right < arr.size(); ++right) { sumWin += arr[right]; while(sumWin >= x) { count += N -right; sumWin -= arr[left]; left++; } } cout << count; } // 挑选宝石 void demo5() { int n, x, y; // 总宝石数、可选宝石数、最低属性值 cin >> n >> x >> y; vector<int> baseVals(n); for(int i = 0; i < n; ++i) { cin >> baseVals[i]; } int ans = 0; for(int mask = 0; mask < (1<<n); ++mask) { int cnt = 0; long long product = 1; for(int i = 0; i < n; ++i) { if(mask & (1<<i)) { cnt++; product *= baseVals[i]; } } if(cnt <= x && product >= y) { ans++; } } cout << ans << endl; } // 整数编码 void demo6() { unsigned long long n; cin >> n; if(n == 0) { cout << "00" << endl; return; } while(n >0) { unsigned char byte = n & 0x7F; n = n >> 7; if(n != 0) { byte |= 0x80; } printf("%02X", byte); } } // 最佳信号覆盖 void demo7() { struct AP { int x, y, s; }; int N, D; // AP数,AP覆盖的最大距离 cin >> N >> D; vector<AP> aps(N); int maxX = 0, maxY = 0; for(int i = 0; i < N; ++i) { cin >> aps[i].x >> aps[i].y >> aps[i].s; maxX = max(maxX, aps[i].x); maxY = max(maxY, aps[i].y); } vector<vector<int> > points; int maxSignal = 0; int bestx = 0, besty = 0; for(int x = 0; x <= maxX + D; ++x) { for(int y = 0; y <= maxY + D; ++y) { int total = 0; for(int k = 0; k < N; ++k) { int d = max(abs(aps[k].x - x), abs(aps[k].y - y)); if(d <= D) { total += aps[k].s / (1 + d); } } if(total > maxSignal) { maxSignal = total; bestx = x; besty = y; } else if(total == maxSignal) { if(x < bestx || (x == bestx && y < besty)) { bestx = x; besty = y; } } } } cout << bestx << " " << besty; } // 冠亚季军 struct Player { int id; long long power; }; bool win(Player&a, Player& b) { // a > b if(a.power == b.power) return a.id < b.id; return a.power > b.power; } void demo8() { long long n; vector<Player> players; int id = 0; while(cin >> n) { players.push_back({id++, n}); } Player no1, no2, no3; while(1) { vector<Player> next; for(int i = 0; i < players.size(); i += 2) { if(i+1 >= players.size()) { next.push_back(players[i]); } else { if(win(players[i], players[i+1])) { next.push_back(players[i]); } else { next.push_back(players[i+1]); } } } players = next; if(players.size() == 3) { if(win(players[0], players[1])) { no3 = players[1]; if(win(players[0], players[2])) { no1 = players[0]; no2 = players[2]; } else { no1 = players[2]; no2 = players[0]; } } else { no3 = players[0]; if(win(players[1], players[2])) { no1 = players[1]; no2 = players[2]; } else { no1 = players[2]; no2 = players[1]; } } break; } else if(players.size() == 4) { Player winner[2]; Player lose[2]; if(win(players[0], players[1])) { winner[0] = players[0]; lose[0] = players[1]; } else { winner[0] = players[1]; lose[0] = players[0]; } if(win(players[2], players[3])) { winner[1] = players[2]; lose[1] = players[3]; } else { winner[1] = players[3]; lose[1] = players[2]; } if(win(winner[0], winner[1])) { no1 = winner[0]; no2 = winner[1]; } else { no1 = winner[1]; no2 = winner[0]; } no3 = win(lose[0], lose[1]) ? lose[0] : lose[1]; break; } } cout << no1.id << " " << no2.id << " " << no3.id << endl; } // 补种未成活胡杨树 void demo9() { int N, M, K; cin >> N; cin >> M; vector<int> trees(N, 1); for(int i = 0; i < M; ++i) { int dead_pos; cin >> dead_pos; trees[dead_pos] = 0; } cin >> K; int left = 0; int dead_count = 0; int res_max = 0; for(int right = 0; right < N; ++right) { if(!trees[right]) { dead_count++; } // if dead_count > K, 不够补活的, 需要left指针右移 while(dead_count > K) { if(!trees[left]) { // 如果left下标的是死树,dead_count需要-1 dead_count--; } left--; } // if dead_cout <= K, 完全够补活的,可以计算当前区间长度 res_max = max(res_max, right - left + 1); } cout << res_max; } // 猜数字 int numYesPosNoCount(int answer, int guess) { vector<int> ans = {answer / 1000, answer % 1000 / 100, answer %100 / 10, answer % 10}; vector<int> gue = {guess / 1000, guess % 1000 / 100, guess %100 / 10, guess % 10}; vector<int> used(4, 0); int count = 0; for(int i = 0; i < ans.size(); ++i) { for(int j = 0; j < gue.size(); ++j) { if(ans[i] == gue[j] && i != j && !used[j]) { count++; used[j] = 1; break; } } } return count; } int numYesPosYesCount(int answer, int guess) { int count = 0; if(answer / 1000 == guess / 1000) count++; if(answer % 1000 / 100 == guess % 1000 / 100) count++; if(answer % 100 / 10 == guess % 100 / 10) count++; if(answer % 10 == guess % 10) count++; return count; } void demo10() { int n; cin >> n; vector<vector<int> > v(n, vector<int>(3)); vector<int> res; string s; int t; for(int i = 0; i < n; ++i) { cin >> v[i][0]; cin >> s; v[i][1] = s[0] - '0'; v[i][2] = s[2] - '0'; } for(int i = 0; i <= 9999; ++i) { int flag = 0; for(int j = 0; j < n; ++j) { if(numYesPosNoCount(i, v[j][0]) == v[j][2] && numYesPosYesCount(i, v[j][0]) == v[j][1]) { continue; } flag = 1; break; } if(!flag) { res.push_back(i); } } if(res.size() == 1) { printf("%04d", res[0]); } else { cout << "NA" << endl; } } // 采购订单 void demo11() { struct product { int id; int price; int amount; }; vector<product> res; map<int, pair<int, int> > low; int n; cin >> n; for(int i = 0; i < n; ++i) { int id, amount, price, prStatus; cin >> id >> amount >> price >> prStatus; if (prStatus == 0) { if(price > 100) { res.push_back({id, price, amount}); } else { if(low.count(id)) { low[id].second += amount; } else { low[id] = {price, amount}; } } } } for(auto& m: low) { int id = m.first; int pri = m.second.first; int amou = m.second.second; if(amou >= 100) { pri = (pri * 9 + 9) / 10; } res.push_back({id, pri, amou}); } sort(res.begin(), res.end(), [](product& a, product& b){ if(a.id != b.id) { return a.id < b.id; } return a.amount > b.amount; }); for(auto it : res) { cout << it.id << " " << it.amount << " " << it.price << endl; } } // 查找单入口区域 int m, n; int dfs_demo12(vector<vector<char> >& grid, vector<vector<bool> >& visited, int x, int y) { } void demo12() { cin >> m >> n; vector<vector<char> > grid(m, vector<char>(n)); vector<vector<bool> > visited(m, vector<bool>(n, false)); for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { cin >> grid[i][j]; } } int maxArea = 0; int sameAreaCount = 0; int maxAreaX = -1, maxAreaY = -1; int dx[] = {1, -1, 0, 0}; int dy[] = {0, 0, 1, -1}; for(int i = 0; i < m; i++) { for(int j = 0; j < n; ++j) { int boundarOCount = 0; int area = 0; int ex = -1, ey = -1; if(grid[i][j] == 'O' && ! visited[i][j]) { visited[i][j] = true; queue<pair<int, int> > q; q.push({i, j}); while(!q.empty()) { int x = q.front().first, y = q.front().second; q.pop(); area++; if(x == 0 || x == m-1 || y == 0 || y == n-1) { boundarOCount++; ex = x;ey = y; } for(int k = 0; k < 4; k++) { int nx = x + dx[k]; int ny = y + dy[k]; if(nx >= 0 && ny >= 0 && nx < m && ny < n) { if(grid[nx][ny] == 'O' && ! visited[nx][ny]) { q.push({nx, ny}); visited[nx][ny] = true; } } } } if(boundarOCount == 1) { if(maxArea < area) { maxArea = area; maxAreaX = ex; maxAreaY = ey; } else if(maxArea == area) { sameAreaCount++; } } } } } if(maxArea == 0) cout << "NULL"; else if(sameAreaCount == 1) { cout << maxAreaX << " " << maxAreaY << " " << maxArea; } else { cout << maxArea; } } // 查找接口成功率最优时间段 void demo13() { int minAverageLost; cin >> minAverageLost; vector<int> lost; int t; int sum = 0; while(cin >> t) { lost.push_back(t); } int n = lost.size(); int bestTime = 0; vector<int> prefixSum(n+1, 0); for(int i = 1; i <= n; ++i) { prefixSum[i] = prefixSum[i-1] + lost[i-1]; } vector<vector<int> > res; // 换成pair<int, int>更好 for(int i = 0; i < n; ++i) { for(int j = i; j < n; ++j) { int sum = prefixSum[j+1] - prefixSum[i]; int len = j-i+1; if( sum <= minAverageLost * len) { if(bestTime < len) { bestTime = len; res.clear(); res.push_back({i, j}); } else if(bestTime == len) { res.push_back({i, j}); } } } } for(int i = 0; i < res.size(); ++i) { cout << res[i][0] << "-" << res[i][1] << " "; } if(res.size() == 0) cout << "NULL"; } // 敌情监控 void demo14() { int n, k, l, t; cin >> n >> k >> l; vector<int> soldiers(n); for(int i = 0; i < n; ++i) { cin >> soldiers[i]; } vector<int> prefixSum(n+1, 0); for(int i = 1; i <= n; ++i) { prefixSum[i] = prefixSum[i-1] + soldiers[i-1]; } for(int m = 0; m < l; ++m) { string cmd; int ti, tj; cin >> cmd >> ti >> tj; if(cmd == "Query") { int minSum = 0; for(int left = ti; left <= tj + 1 -k; ++left) { int sum = prefixSum[left+k-1] - prefixSum[left-1]; minSum = min(minSum, sum); } cout << min << endl; } else if(cmd == "Add") { soldiers[ti-1] += tj; } else if(cmd == "Sub") { soldiers[ti-1] -= tj; } else { // input error } for(int i = ti; i <= n; ++i) { prefixSum[i] = prefixSum[i-1] + soldiers[i-1]; } } } // 斗地主之顺子 void demo15() { vector<string> cardVal = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; set<string> cards; string s; while(cin >> s) { cards.insert(s); } bool found = false; for(int i = 0; i < cardVal.size(); ++i) { int j = i; if(cards.count(cardVal[j])) { vector<string> temp; while(j < cardVal.size() && cards.count(cardVal[j])) { temp.push_back(cardVal[j]); j++; } if(temp.size() >= 5) { found = true; for(int k = 0; k < temp.size(); ++k) { cout << temp[k]; if(k != temp.size() -1) cout << " "; } cout << end; } } i = j -1; } if(!found) { cout << "NO"; } } // 风险投资计划 void demo16() { int m, n, x, y; cin >> m >> n >> x >> y; vector<int> prod; int e, r; while(cin >> e >> r) { if(r <= x) { prod.push_back(e); } } sort(prod.begin(), prod.end(), [](int a, int b){return a> b;}); // 降序 n = prod.size(); int sumE = 0, cost = 0; #if 1 for(int i = 0; i < n; ++i) { cost += y ; // 每个产品按最高y投资 if(cost <= m) {sumE += y*prod[i];} else { int left = m - (cost - y); sumE += left * prod[i]; break; // 超出预算 } } int max = (sumE % 100) / 10 >= 5 ? sumE/100 + 1 : sumE/100; cout << max << endl; #else int money = m; double profit = 0.0; for(int i = 0; i < n && money > 0; ++i) { int invest = min(y, money); profit += invest * prod[i] / 100.0; money -= y; } cout << (int)(profit + 0.5) << endl; #endif } // 高矮个子排队 void demo17() { vector<int> heights; string s; while(cin >> s) { for(int i = 0; i < s.size(); ++i) { if(s[i] >= '0' && s[i] <= '9') { continue; } cout << "[ ]"; return; } heights.push_back(stoi(s)); } for(int i = 0; i < heights.size() - 1; ++i) { if(i % 2==0 && heights[i] < heights[i+1]) { swap(heights[i], heights[i+1]); } else if(i%2 == 1 && heights[i] > heights[i+1]) { swap(heights[i], heights[i+1]); } } for(int i = 0; i < heights.size(); ++i) { cout << heights[i]; if(i != heights.size()-1) cout << " "; } cout << endl; } // 构成正方形的数量 void demo18() { int n; vector<pair<int, int> > pos; set<pair<int, int> > us; cin >> n; for(int i = 0; i < n; ++i) { int x, y; cin >> x >> y; pos.push_back({x, y}); us.insert({x, y}); } int count = 0; for(int i = 0; i < pos.size(); ++i) { int ax = pos[i].first, ay = pos[i].second; for(int j = i+1; j < pos.size(); ++j) { int bx = pos[j].first, by = pos[j].second; int tx = bx - ax; int ty = by - ay; // 旋转90° int dx = ax - ty, dy = ay + tx;// d点是b逆时针旋转90 int cx = bx - ty, cy = by + tx;// c点是a顺时针旋转90 if(us.count({dx, dy}) && us.count({cx, cy})) { count++; } dx = ax + ty, dy = ay - tx; // d点是 b顺时针旋转90 cx = bx + ty, cy = by - tx; // c点是 a逆时针旋转90 if(us.count({dx, dy}) && us.count({cx, cy})) { count++; } } } cout << count/4 << endl; } // 恢复数字序列 void demo19_1() { string s; int digistLen; cin >> s >> digistLen; map<char, int> mp; for(int i = 0; i < s.size(); ++i) { mp[s[i]]++; } int left = 1; int right = left + digistLen -1; while(right <= 1000) { int windowLeft = left, windowRight = right; string t(""); for(; windowLeft <= windowRight; ++windowLeft) { t += to_string(windowLeft); } map<char, int> mt; bool match = true; for(int i = 0; i < t.size(); ++i) { mt[t[i]]++; } for(auto& [key, value] : mp) { if(mt[key] != value) { match = false; break; } } if(match) { cout << left; return; } left++; right++; } } void demo19_2() { } // 精准核算检测 struct Solution20 { int getCheckPeople(vector<vector<int> >& mat, vector<int>& infected) { int count = 0; queue<int> q; int infectedCount = infected.size(); int totol = mat.size(); vector<bool> visited(totol, false); // 默认所有人都未被检查 for(int i = 0; i < infectedCount; ++i) { visited[infected[i]] = true; q.push(infected[i]); } while(!q.empty()) { vector<int> t = mat[q.front()]; q.pop(); for(int j = 0; j < t.size(); ++j) { // // j号未被访问,且与感染者有接触 if(visited[j] == false && t[j] == 1) { q.push(j); visited[j] = true; // 标记为已访问 } } } for(int i = 0; i < totol; ++i) { if(!visited[i]) count++; } return count - infectedCount; } }; int main() { demo1(); return 0; }
史记_魏公子列传
魏公子,魏无忌是也,也即信陵君。 魏昭王去世后,并未手足相残,其同父异母的弟弟做了魏王,自己被封为信陵君。 公子无忌礼贤下士,门客三千,因此各诸侯不敢加兵谋魏十余年。 魏王因公子无忌有能力提前知晓赵王行动,便对其产生忌惮。
你好,世界
这是我基于 CentOS 9 + Nginx + Hugo 搭建的个人博客。 域名:zrq2.batch.icu HTTPS:Let’s Encrypt 博客系统:Hugo 🚀 欢迎访问!