文章目录
- 2023年OD 招聘C卷&D卷原题
- 1.停车场车辆统计【数组、贪心】
- 2.英文输入法【哈希】
- 3.API集群负载统计【模拟、字符串】
- 4.提取字符串中的最长数学表达式并计算【栈】
- 5.开源项目热榜【模拟、排序】
- 6.虚拟游戏理财【动态规划】
- 7.万能字符单词拼写【哈希表】
- 8.寻找身高相近的小朋友【排序】
- 9.精准核酸检测【DFS】
- 11.贪心歌手【贪心】
- 12.简易内存池
- 13.最大可购买的宝石数量【不定滑窗】
- 14.游戏分组:深搜
- 18.小朋友来自多少小区【贪心】
- ==23.环中最长子串2 :字符串==
- 24.分割均衡字符串【贪心】
- ==26.分披萨:动态规划==
- 27.整数对最小和
- ==28.路口最短时间问题:递归 时间计算==
- 29.字符串变换最小字符串:字符串
- 30.回转寿司【单调栈】
- ==32.查找接口成功率最优时问段:数组 排序 字符串==
- 33.项目排期【二分】
- 34.密码解密:字符串
- 35.机场航班调度程序【模拟、排序】
- 36.求幸存数之和:数组
- 37.结队编程【数组】
- 38.求字符串中所有整数的最小和
- 42.根据IP查找城市
- 43.最长子字符串的长度(一):字符串
- ==44.会议室占用时间==
- 45.悄悄话【DFS】
- 46.分配土地【贪心】
- 47.电脑病毒感染:广搜
- 48.来自异国的客人【进制转换】
- 51.小明找位置
- 52.素数之积【递归 循环 整数范围】
- 54.两个字符串间的最短路径问题【DP】
- 55.执行时长:数组【B】
- 56.数组去重和排序【模拟,排序】
- 57.测试用例执行计划【哈希】
- 58.5G网络建设
- 59.亲子游戏【BFS】
- 60.螺旋数字矩阵【模拟、数组】
- 61.最大N个数与最小N个数的和【哈希】
- 62.火星文计算2【字符串、单调栈】
- ==67.田忌赛马: 编程基础==
- 68.单词接龙【B】
- 69.五子棋迷【B】
- 70.找出两个整数数组中同时出现的整数【B】
- 71、Wonderland
- 73.任务处理【贪心】
- 75.计算三叉搜索树的高度
- 76.攀登者1: 【模拟、数组】
- 78.多段线数据压缩【数组 栈 递归 矩阵 循环】
- 79.文件缓存系统
- 82.启动多任务排序
- 83.推荐多样性:字符串 滑窗
- 86.跳马问题【BFS】
- 87.矩阵匹配: 二分查找 DFS搜索
- 89.伐木工【贪心】
- 90.园区参观路径
- 91.最小矩阵宽度【不定滑窗】
- 92.机器人仓库搬砖: 二分查找 字符串 编程基础 数组
- 93.密码输入检测
- 95.考勤信息: 字符串
- 97.数据单元的变量替换:字符串 编程基础
- 99.篮球游戏【队列】
- 102.内存冷热标记【哈希】
- 103.求最多可以派出多少支团队【贪心】
- 104.孙悟空吃蟠桃: 二分查找
- 105.贪吃的猴子
- 107.寻找最富裕的小家庭【DFS】
- 108.抢7游戏
- 109.分月饼: 动态规划
- 110.求幸存数之和: 数组
- 113.二叉树的广度优先遍历: 树
- 115.反射计数
- 117.围棋的气【哈希】
- 字符串表达式求值
- 2023Q2B-选修课
- 2023Q1A-相同数字的积木游戏
- 2023Q1A-寻找密码
- 2023C-找最小数【单调栈】
- 2023Q1A-两数之和绝对值最小
- 2023Q1A-双十一
- 2023Q1A-快递货车
- 2023C-停车找车位【贪心】
- 2023Q1A-贪心的商人【DP/贪心】
- 2023C-身高体重排序【模拟】
- 2023B-拔河比赛【模拟、排序】
- 2023C-身高排序【模拟、排序】
- 2023B-磁盘容量【模拟、排序】
- 2023B-日志时间排序【模拟、排序】
- 2023C-最低位排序【模拟、排序】
- 2023C-智能成绩表【模拟、排序】
- 2023B-VLAN资源池【模拟、排序】
- 2023B-查字典
- 2023C-字符串分割(二)
- 2023C-GPU调度
- 2023C-回收银饰
- 2023C-小明能到达的最大坐标值
- 2023C-比赛的冠亚季军【模拟、数组】
- 2023C-灰度图恢复
- 2023C-高效货运【模拟、数学】
- 2023C-整数分解
- 2023C-找朋友【单调栈】
- 2023C-回转寿司
- ==2023C-攀登者2==
- ==2023C-解密犯罪时间==
- 2023C-CPU算力分配
- 2023C-求满足条件的最长子串的长度【不定滑窗】
- 2023C-字符串摘要【不定滑窗】
- 2023C-最长的指定瑕疵度的元音子串
- 2023C-分班【DP】
- 2023C-石头剪刀布游戏
- 2023C-座位调整
- 2023C-在规定时间内获得的最大报酬
- 2023C-环中最长子串
- 2023C-部门人力分配
- 2023C-可以组成网络的服务器【DFS/BFS】
- 2023C-图像物体的边界【DFS/BFS】
- 2023C-地图寻宝【DFS/BFS】
- 2023C-跳马问题
- 2023C-周末爬山
- 2023C-堆内存申请
- 2023C-找到它【回溯】
- 2023C-考古学家【回溯】
- 2023C-最长连续手牌【回溯】
- 2023C-寻找最优的路测线路【BFS】
- 2023C-查找一个有向网络的头节点和尾节点【BFS】
- 2023C-通过软盘拷贝文件【DP】
2023年OD 招聘C卷&D卷原题
(出现频率:红色(5次)>蓝色(4次)>绿色(3次)>黄色(2次))
刷题建议:
一、基础较好:必刷红蓝绿共26道题目&对应的知识点
二、基础一般:必刷红蓝绿黄共62道题目&对应的知识点
三、基础较差:建议先学知识点,再刷题目
1.停车场车辆统计【数组、贪心】
#include<bits/stdc++.h>
using namespace std;
int main(){
int res = 0;
string cars = "";
getline(cin,cars);//getline用于输入字符串
string s;
for(int i=0;i<cars.size();i++){//循环操作摘出逗号
if(cars[i]!=',') s+=cars[i];
}
while(s.find("111")!=-1){
s.replace(s.find("111"),3,"x");
}
while(s.find("11")!=-1){
s.replace(s.find("11"),2,"x");
}
while(s.find("1")!=-1){
s.replace(s.find("1"),1,"x");
}
for(int i=0;i<s.size();i++){
if(s[i] == 'x') res++;
}
printf("%d\n",res);
return 0;
}
2.英文输入法【哈希】
#include<bits/stdc++.h>
using namespace std;
set<string> res;//set自动去重且排序
set<string> tmp;
int main(){
string s;
string pre = "";
getline(cin,s);
getline(cin,pre);
for(int i=0;i<s.size();i++){
if(!isalpha(s[i])&&!isspace(s[i])) s[i] = ' ';//将标点符号替换为空格
}
// 分割字符串中的单词
string buffer = "";
istringstream is(s);
while(is>>buffer){
tmp.insert(buffer);
}
for(set<string>::iterator it=tmp.begin();it!=tmp.end();it++){
string str = *(it);
if(str.find(pre)==0){//从第一个字符开始匹配才可以联想
res.insert(str);
}
}
if(res.empty()){// 如果没有联想到,则输出输入的值
cout<<pre<<endl;
}
for(set<string>::iterator it=res.begin();it!=res.end();it++){
cout<<*(it)<<' ';
}
return 0;
}
3.API集群负载统计【模拟、字符串】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
getchar();
vector<vector<string>> v;
while(n--){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
vector<string> words;
while(getline(is,buffer,'/')){ //注意会取到空字符串,因为以“/”开头,截取到它之前的空字符串
words.push_back(buffer);
}
v.push_back(words);
}
int l;
string key;
cin>>l>>key;
int res = 0;
for(auto words:v){
if(words.size()<=l) continue;
else if(words[l] == key) res++;
}
cout<<res<<endl;
return 0;
}
4.提取字符串中的最长数学表达式并计算【栈】
- 从输入的字符串中提取出所有合法的数学表达式
sort
选出长度最长的表达式- 遍历字符串表达式,将中缀转换为后缀表达式
- 计算表达式
#include<bits/stdc++.h>
using namespace std;
string ops = "-+*";
vector<string> expression;
bool cmp(string s1,string s2){
return s1.size()>s2.size();
}
int res = 0;
stack<int> num;
stack<char> op;
//定义四个操作符的优先级
map<char,int> mp = {{'+',1},{'-',1},{'*',2}};
//中缀转后缀,再进行表达式运算
void eval(){
int b = num.empty()? 0: num.top();
if(!num.empty()) num.pop();
int a = num.empty()? 0: num.top();
if(!num.empty()) num.pop();
char c = op.top();
op.pop();
int x;
if(c == '+') x = a+b;
else if(c == '-') x = a-b;
else if(c == '*') x = a*b;
num.push(x);
}
int main(){
string s;
getline(cin,s);
//改造为多个合法表达式
for(int i=0;i<s.size();i++){
if(!isdigit(s[i])&&s[i]!='-'&&s[i]!='+'&&s[i]!='*'){
s[i] = ' ';
}
}
for(int i=0;i<s.size();i++){
if(ops.find(s[i])!=-1&&!isdigit(s[i-1])){
s[i] = ' ';
s[i-1] = ' ';
}
}
// cout<<s<<endl;
//将多个表达式拆分
string buffer;
istringstream is(s);
while(is>>buffer) expression.push_back(buffer);
//对表达式按长度进行排序
sort(expression.begin(),expression.end(),cmp);
//得到最长的表达式
string ls = *expression.begin();
//扫描表达式,进行运算
for(int i=0;i<ls.size();i++){
if(isdigit(ls[i])){
int j = i, product = 0;
while(j<ls.size()&&isdigit(ls[j])){
product = product*10+ls[j]-'0';
j++;
}
num.push(product);
i = j-1;
}else{
while(op.size()&&mp[op.top()]>=mp[ls[i]]) eval();
op.push(ls[i]);
}
}
while(op.size()) eval();
cout<<num.top()<<endl;
return 0;
}
5.开源项目热榜【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
struct Project{
string name;
int val;
};
//结构体排序
bool cmp(Project x,Project y){
if(x.val == y.val){
return x.name<y.name;
}else{
return x.val>y.val;
}
}
int main(){
int n;
cin>>n;
int ww,ws,wf,wi,wm;
cin>>ww>>ws>>wf>>wi>>wm;
//定义结构体数组
vector<Project> project(n);
for(int i=0;i<n;i++){
string name;
cin>>name;
int nr_watch, nr_start, nr_fork, nr_issue, nr_mr;
cin>>nr_watch>> nr_start>>nr_fork>>nr_issue>> nr_mr;
int val = ww*nr_watch+ws*nr_start+wf*nr_fork+wi*nr_issue+wm*nr_mr;
project[i].name = name;
project[i].val = val;
}
sort(project.begin(),project.end(),cmp);
for(int i=0;i<n;i++){
cout<<project[i].name<<endl;
}
return 0;
}
6.虚拟游戏理财【动态规划】
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, totalAmount, X;
cin >> n >> totalAmount >> X; //产品数、总投资额、可接受的总风险
vector<int> returnRateLst(n); //产品投资回报序列
vector<int> riskLst(n); //产品风险序列
vector<int> maxAmountLst(n); //最大投资额度序列
for (int i = 0; i < n; i++) {
cin >> returnRateLst[i];
}
for (int i = 0; i < n; i++) {
cin >> riskLst[i];
}
for (int i = 0; i < n; i++) {
cin >> maxAmountLst[i];
}
int maxReturn = 0;
vector<vector<int>> pairs(2, vector<int>(2, 0));
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
//如果风险值大于可接受的总风险 ,则进入下一个循环
// 由于加上了两个产品的风险值,则此情况必定是选择两个产品的情况
if (riskLst[i] + riskLst[j] > X) {
continue;
}
int iAmount, jAmount;
if (maxAmountLst[i] + maxAmountLst[j] <= totalAmount) { //如果i、j两个的最大投资额度之和小于等于总投资额,则直接各取其最大投资额
iAmount = maxAmountLst[i];
jAmount = maxAmountLst[j];
} else { //如果i、j两个的最大投资额度之和大于总投资额
if (returnRateLst[i] >= returnRateLst[j]) { //则选取投资回报更多的产品进行投资
iAmount = min(maxAmountLst[i], totalAmount);
jAmount = totalAmount - iAmount;
} else {
jAmount = min(maxAmountLst[j], totalAmount);
iAmount = totalAmount - jAmount;
}
}
int curReturn = iAmount * returnRateLst[i] + jAmount * returnRateLst[j]; //记录下当前情况下的回报
// 如果当前情况下的回报大于已经记录下的最大回报,则更新记录
if (curReturn > maxReturn) {
maxReturn = curReturn;
pairs[0][0] = i; //第一个投资的产品序号
pairs[0][1] = iAmount; //第一个投资的产品数目
pairs[1][0] = j;
pairs[1][1] = jAmount;
}
}
}
//考虑只选择1种产品i的情况
for (int i = 0; i < n; i++){
if (riskLst[i] > X) {
continue;
}
int iAmount = min(maxAmountLst[i], totalAmount);
int curReturn = iAmount * returnRateLst[i];
if (curReturn > maxReturn) {
maxReturn = curReturn;
pairs[0][0] = 0;
pairs[0][1] = 0;
pairs[1][0] = i;
pairs[1][1] = iAmount;
}
}
//构建答案序列,除了最终的i和j位置需要调整为最优的i_amount和j_amount,
//其他位置所选取的份额都是0,因为最多只能投资2个理财产品
vector<int> ans(n, 0);
ans[pairs[0][0]] = pairs[0][1];
ans[pairs[1][0]] = pairs[1][1];
for (int i = 0; i < n; i++) {
cout << ans[i] << " ";
}
return 0;
}
7.万能字符单词拼写【哈希表】
解题思路
-
统计元素频率,很显然需要使用哈希表进行。
-
唯一需要特殊处理的就是字符
?
可以代表万能字符。 -
假设某一单词
word
和字符串chars
对应的计数器分别为cnt_word
和cnt_chars
,问号字符?
出现的次数为num
。那么在逐一比较word
中字符出现次数和chars
中元素出现字符时,若出现cnt_word[k] > cnt_chars[k]
,则可以使用cnt_word[k] - cnt_chars[k]
个?
来作为万能字符。若发现此时?
出现的次数为num
已经小于cnt_word[k] - cnt_chars[k]
,则无法拼凑出单词word
。
#include<bits/stdc++.h>
using namespace std;
int res = 0;
//判断是否能让chars里的字符表示word
bool check(unordered_map<char,int> cntChars,unordered_map<char,int> cntWord,int num){
for(auto kv:cntWord){
char k = kv.first;
if(cntWord[k]<=cntChars[k]){
continue;
}else{
num-=(cntWord[k]-cntChars[k]);
if(num<0) return false;
}
}
return true;
}
int main(){
int n;
cin>>n;
vector<string> words(n);
for(int i=0;i<n;i++){
cin>>words[i];
}
//统计chars里的各个字符的个数
string chars;
cin>>chars;
unordered_map<char,int> cntChars;
for(char c:chars){
cntChars[c]++;
}
//获得?的个数
int num = cntChars['?'];
//统计word里的各字符的个数
for(string word : words){
unordered_map<char,int> cntWord;
for(char c:word){
cntWord[c]++;
}
res+=check(cntChars,cntWord,num)? 1 : 0;
}
cout<<res<<endl;
}
8.寻找身高相近的小朋友【排序】
#include<bits/stdc++.h>
using namespace std;
int h,n;
bool cmp(int x,int y){
if((abs(x-h)) == (abs(y-h))){
return x<y;
}else{
return (abs(x-h))<(abs(y-h));
}
}
int main(){
cin>>h>>n;
vector<int> child(n);
for(int i=0;i<n;i++){
cin>>child[i];
}
sort(child.begin(),child.end(),cmp);
for(int i=0;i<n;i++){
cout<<child[i]<<' ';
}
}
9.精准核酸检测【DFS】
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> g;
void dfs(vector<int>& vis, int i){
for(int j=0;j<g[i].size();j++){
if(g[i][j] && vis[i] && !vis[j]){
vis[j] = 1;
dfs(vis,j);
}
}
}
int main(){
int res = 0;
// 总人数
int n;
cin>>n;
getchar();
string s;
getline(cin,s);
string buffer;
istringstream is(s);
vector<int> illed;
while(getline(is,buffer,',')){
illed.push_back(stoi(buffer));
}
// 记录确诊的人
vector<int> vis(n);
for(int i=0;i<illed.size();i++){
vis[illed[i]] = 1;
}
// 每个人员之间是否有接触
vector<vector<int>> isconnected(n);
for(int i=0;i<n;i++){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
while(getline(is,buffer,',')){
isconnected[i].push_back(stoi(buffer));
}
}
g = isconnected;
for(int i=0;i<n;i++){
if(vis[i]){
dfs(vis,i);
}
}
for(int i=0;i<n;i++){
if(vis[i]) res++;
}
cout<<res - illed.size()<<endl;
}
11.贪心歌手【贪心】
题解思路
我们并不需要按照歌手的时间线来考虑问题,而是按照某一天能够在哪个城市获得的钱数最多来考虑问题的。
使用优先队列来维护该过程。具体过程如下:
- 构建一个以最大值为排序依据的优先队列(即大根堆)
heap
- 将每一个城市的
(M, D)
储存在堆中。 - 循环
X
次,表示最多可以停留X
天再进行卖唱。- 弹出堆顶元素
M, D
,此时可以赚到M
,即更新ans += M
- 计算衰减后该城市能够赚到的钱
M -= D
。 - 如果
M
衰减了D
之后,仍大于0
,说明还有可能继续在这个城市赚钱,需要将(M, D)
重新入堆
- 弹出堆顶元素
- 注意在循环中,必须判断
heap
的长度是否大于0
。如果等于0
,说明优先队列中无元素,所有的城市赚的钱都衰减到0
了,此时可以直接退出循环。
#include<bits/stdc++.h>
using namespace std;
int main() {
//必须在 T 天内赶到
//途径 N 座城市
int T, N;
cin >> T >> N;
//每两座城市之间耗费的时间
vector<int> days(N+1);
for (int i = 0; i < N+1; i++) {
cin >> days[i];
}
priority_queue<pair<int, int>> heap;
for (int i = 0; i < N; i++) {
//第一天卖唱可以赚 M
//后续每天的收入会减少 D
int M, D;
cin >> M >> D;
heap.push({M, D});
}
//计算可以卖唱的总天数X
int X = T;
for (int i = 0; i < N+1; i++) {
X -= days[i];
}
int ans = 0;
for (int i = 0; i < X; i++) {
//所有的城市赚的钱都衰减到0
if (heap.empty()) {
break;
}
auto city = heap.top();
heap.pop();
int M = city.first;
int D = city.second;
ans += M;
M -= D;
if (M > 0) {
heap.push({M, D});
}
}
cout << ans << endl;
return 0;
}
12.简易内存池
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
vector<int> vis(N);
struct ST{
int s;
int e;
int len;
};
int main(){
//期望申请的内存字节数
int n;
cin>>n;
int x,y;
while(cin>>x>>y){
if(x<0||x>=100||y<=0||x+y>=100){
cout<<-1;
return 0;
}
for(int i=x;i<x+y;i++){
if(vis[i] == 1){
cout<<-1;
return 0;
}
vis[i] = 1;
}
}
vector<ST> v;
for(int i=0;i<N;i++){
if(vis[i] == 0){
int x = i,y;
int j = i;
while(j<N && vis[j] == 0){
y = j;
j++;
}
int len = y-x+1;
v.push_back({x,y,len});
i = j-1;
}
}
sort(v.begin(),v.end(),[](ST st1, ST st2){
if(st1.len == st2.len){
return st1.s<st2.s;
}else return st1.len < st2.len;
});
for(auto x:v){
if(x.len>=n){
cout<<x.s;
return 0;
}
}
cout<<-1;
}
13.最大可购买的宝石数量【不定滑窗】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> gems(n);
for(int i=0;i<n;i++) cin>>gems[i];
int v;
cin>>v;
int l = 0,r;
int tmpRes = 0;
int res = 0;
int val = 0;
for(r=0;r<n;r++){
val+=gems[r];
tmpRes++;
while(val>v){
val-=gems[l];
l++;
tmpRes--;
}
if(val<=v){
res = max(res,tmpRes);
}
}
cout<<res<<endl;
}
14.游戏分组:深搜
解题思路
两队的总评分total_sum
是确定的。将问题转化为,在10
个元素中挑选出5
个元素,使得这5
个元素的和尽可能接近total_sum
的一半即total_sum / 2
。
假定元素和较小的那组为A
组,较大的那组为B
组,由于sum(A) <= total_sum / 2 <= sum(B)
始终成立,因此可以只考虑小于等于total_sum / 2
的A
组情况即可。
在10
个元素中挑选出5
个元素的组合问题,很容易想到直接使用回溯来解决。由于只考虑A
组情况,所以当发现path_sum > total_sum / 2
时,可以进行剪枝操作。
#include<bits/stdc++.h>
using namespace std;
int res = INT_MAX;
vector<bool> vis(10,false);
vector<int> subset;
void dfs(vector<int> peo, vector<bool>& vis, int target,int sum){
if(subset.size() == 5){
int sum_A = accumulate(subset.begin(),subset.end(),0);
if(sum_A>target) return ;
else{
res = min(res,abs(sum - 2*sum_A));
return ;
}
}
for(int i=0;i<peo.size();i++){
if(!vis[i]){
vis[i] = true;
subset.push_back(peo[i]);
dfs(peo,vis,target,sum);
vis[i] = false;
subset.pop_back();
}
}
}
int main(){
vector<int> peo(10);
for(int i=0;i<10;i++){
cin>>peo[i];
}
int sum = accumulate(peo.begin(),peo.end(),0);
int target = sum/2;
dfs(peo,vis,target,sum);
cout<<res<<endl;
}
18.小朋友来自多少小区【贪心】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
istringstream is(s);
int x;
map<int,int> mp;
while(is>>x){
mp[x]++;
}
int res = 0;
for(auto x:mp){
int peo = x.first+1; //一个小区的人数
int child = x.second; //已经记录的小孩人数
if(child<=peo){
res+=peo;
}else{
while(child-peo>=0){
res+=peo;
child-=peo;
}
if(child) res+=peo;
}
}
cout<<res<<endl;
}
23.环中最长子串2 :字符串
#include <iostream>
#include <string>
using namespace std;
int main() {
// 创建一个字符串变量,用于存储用户输入
string input;
// 读取用户输入的字符串
getline(cin, input);
// 获取字符串的长度
int len = input.size();
// 初始化'o'字符的计数器
int num = 0;
// 遍历字符串,统计'o'字符的数量
for (char chr : input) {
if (chr == 'o') {
num += 1;
}
}
// 如果'o'字符出现的次数是偶数,则输出字符串的长度
if (num % 2 == 0) {
cout << len << endl;
} else {
// 如果'o'字符出现的次数是奇数,则输出字符串长度减1
cout << len - 1 << endl;
}
return 0;
}
24.分割均衡字符串【贪心】
#include<bits/stdc++.h>
using namespace std;
int main(){
int res = 0;
string s;
getline(cin,s);
int n = s.size();
map<char,int> mp;
for(int i=0;i<n;i++){
mp[s[i]]++;
if(mp['X'] == mp['Y'] && mp['X']!=0){
res++;
mp.clear();
}
}
cout<<res<<endl;
}
26.分披萨:动态规划
1.环形处理:由于披萨是环形排列的,所以在选择披萨时需要考虑边界情况,即当选择了最左边或最右边的披萨后,如何循环到另一端。
2.动态规划:使用一个二维数组dp 作为记忆化存储,其中dp[L][R] 表示从左边界L到右边界R能够获得的最大美味值。如果dp[L][R] 已经被计算过,则直接返回该值。
3.递归计算:定义一个递归函数来计算dp[L][R]。 如果a[L] (左边界的披萨美味值)大于a[R]
(右边界的披萨美味值),则选择L并将L向右移动- -位;否则选择R并将R向左移动一位。这样递归地选择下-步,直到只剩下一块披萨。
4.递归基:当左右边界相遇时(即L == R),说明只剩下一块披萨,直接返回这块披萨的美味值作为递归基。
5.状态转移:在递归过程中,dp[L][R] 的值是通过比较选择左边界披萨和右边界披萨后,剩下披萨的最大美味值之和来确定的。
#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::max 函数
using namespace std;
int n; // 披萨的数量
vector<int> a; // 每块披萨的美味值
vector<vector<int>> dp; // 记忆化数组,用于存储已计算过的状态
// 计算最大美味值的函数
int allocation(int L, int R) {
if (dp[L][R] != -1) {
return dp[L][R]; // 如果已计算过,直接返回结果
}
if (a[L] > a[R]) {
L = (L + 1) % n; // 左边披萨更美味,吃掉左边的
} else {
R = (R + n - 1) % n; // 右边披萨更美味,吃掉右边的
}
if (L == R) {
dp[L][R] = a[L]; // 只剩一块披萨时,返回其美味值
} else {
// 否则,递归计算剩下披萨的最大美味值,并更新记忆化数组
dp[L][R] = max(a[L] + allocation((L + 1) % n, R), a[R] + allocation(L, (R + n - 1) % n));
}
return dp[L][R]; // 返回当前状态下的最大美味值
}
int main() {
cin >> n; // 输入披萨的数量
a.resize(n); // 调整数组大小以存储每块披萨的美味值
for (int i = 0; i < n; ++i) {
cin >> a[i]; // 输入每块披萨的美味值
}
dp.assign(n, vector<int>(n, -1)); // 初始化记忆化数组
int ans = 0; // 初始化最大美味值为 0
for (int i = 0; i < n; ++i) {
// 更新最大美味值,allocation函数计算从当前披萨开始的最大美味值
ans = max(ans, allocation((i + 1) % n, (i + n - 1) % n) + a[i]);
}
cout << ans << endl; // 输出最多能吃到的披萨的美味值
return 0;
}
27.整数对最小和
- 直接暴力
n
对 - 选前
k
个最小的整数对求和
28.路口最短时间问题:递归 时间计算
#include<bits/stdc++.h>
using namespace std;
// 定义四个方向的偏移量:上、右、下、左
const int offsets[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int calcTime(vector<vector<int>>& lights, int timePerRoad, int rowStart, int colStart, int rowEnd, int colEnd) {
int n = lights.size(), m = lights[0].size();
// 初始化距离数组
vector<vector<vector<int>>> dist(n, vector<vector<int>>(m, vector<int>(4, INT_MAX)));
for (int k = 0; k < 4; ++k) {
dist[rowStart][colStart][k] = 0;
}
// 使用优先队列
priority_queue<tuple<int, int, int, int, int, int>, vector<tuple<int, int, int, int, int, int>>, greater<>> pq;
for (int k = 0; k < 4; ++k) {
pq.push({0, rowStart, colStart, -1, -1, k});
}
while (!pq.empty()) {
auto [v, x, y, px, py, direction] = pq.top();
pq.pop();
for (int k = 0; k < 4; ++k) {
int new_x = x + offsets[k][0];
int new_y = y + offsets[k][1];
if (new_x < 0 || new_x >= n || new_y < 0 || new_y >= m || (new_x == px && new_y == py)) continue;
int new_cost = v + timePerRoad;
if ((direction + 1) % 4 != k) // 如果不是右转
new_cost += lights[x][y];
if (new_cost < dist[new_x][new_y][k]) {
dist[new_x][new_y][k] = new_cost;
pq.push({new_cost, new_x, new_y, x, y, k});
}
}
}
return *min_element(dist[rowEnd][colEnd].begin(), dist[rowEnd][colEnd].end());
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> lights(n, vector<int>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> lights[i][j];
}
}
int timePerRoad;
cin >> timePerRoad;
int rowStart, colStart, rowEnd, colEnd;
cin >> rowStart >> colStart >> rowEnd >> colEnd;
cout << calcTime(lights, timePerRoad, rowStart, colStart, rowEnd, colEnd) << endl;
return 0;
}
29.字符串变换最小字符串:字符串
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
string str = s;
sort(str.begin(),str.end());
int n = s.size();
int i;
char c;
int pos = -1;
for(i = 0;i<n;i++){
if(s[i] == str[i]) continue;
else{
c = str[i];
pos = s.rfind(c); //字符串从后往前查找是否有该元素
break;
}
}
if(pos!=-1){
s[pos] = s[i];
s[i] = c;
}
cout<<s<<endl;
}
30.回转寿司【单调栈】
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> food;
int x;
while(cin>>x){
food.push_back(x);
}
int len = food.size();
vector<int> price(len);
for(int i=0;i<len;i++){
int flag = 0;
for(int j=(i+1)%len;j!=i;j = (j+1)%len){
if(food[j]<food[i]){
price[i] = food[i]+food[j];
flag = 1;
break;
}
}
if(!flag) price[i] = food[i];
}
for(auto x:price) cout<<x<<' ';
}
32.查找接口成功率最优时问段:数组 排序 字符串
解题思路
1.首先:我们需要读取输入的数据,包括容忍的平均失败率和失败率数组。
2.然后:我们创建一个累积和数组,用于快速计算任意时间段的失败率总和。这个数组的每个元素都是从数组开始到当前位置的失败率的总和。
3.接下来:我们遍历所有可能的时间段,包括所有可能的开始和结束索引。对于每个时间段,我们计算其失败率总和,然后计算其平均失败率。我们可以通过查找累积和数组来快速计算失败率总和。
4.对于每个时间段,我们检查其平均失败率是否小于等于容忍的平均失败率。如果是,我们就找到了一个满足条件的时间段。
5.我们需要找到最长的满足条件的时间段。因此,我们需要跟踪找到的最长时间段的长度。如果我们找到一个比当前最长时间段更长的时间段,我们就更新最长时间段的长度,并清空结果列表,然后将新的时间段添加到结果列表中。如果我们找到一个和当前最长时间段一样长的时间段,我们就将它添加到结果列表中。
6.最后,我们检查结果列表。如果结果列表为空,说明我们没有找到任何满足条件的时间段,我们就输出"NULL"。否则,我们输出所有满足条件的时间段。如果有多个时间段,我们需要按照开始索引从小到大的顺序输出。
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;
int main() {
// 容忍的平均失败率
int toleratedAverageLoss;
cin >> toleratedAverageLoss;
// 读取失败率数组
vector<int> failureRates;
string line;
getline(cin >> ws, line);
istringstream iss(line);
int num;
while (iss >> num) {
failureRates.push_back(num);
}
int arrayLength = failureRates.size();
// 创建一个累积和数组,用于快速计算任意时间段的失败率总和
vector<int> cumulativeSum(arrayLength);
cumulativeSum[0] = failureRates[0];
for (int i = 1; i < arrayLength; i++) cumulativeSum[i] = cumulativeSum[i - 1] + failureRates[i];
// 存储满足条件的时间段的开始和结束索引
vector<pair<int, int>> validPeriods;
int maxLength = 0;
for (int start = 0; start < arrayLength; start++) {
for (int end = start; end < arrayLength; end++) {
int sum = start == 0 ? cumulativeSum[end] : cumulativeSum[end] - cumulativeSum[start - 1];
int length = end - start + 1;
int toleratedLoss = length * toleratedAverageLoss;
// 如果这个时间段的平均失败率小于等于容忍的平均失败率
if (sum <= toleratedLoss) {
// 如果这个时间段比之前找到的时间段更长,清空结果列表并添加这个时间段
if (length > maxLength) {
validPeriods.clear();
validPeriods.push_back({start, end});
maxLength = length;
}
// 如果这个时间段和之前找到的最长时间段一样长,添加这个时间段
else if (length == maxLength) {
validPeriods.push_back({start, end});
}
}
}
}
// 如果没有找到满足条件的时间段,输出"NULL"
if (validPeriods.empty()) {
cout << "NULL" << endl;
}
// 否则,输出所有满足条件的时间段
else {
sort(validPeriods.begin(), validPeriods.end());
for (auto& period : validPeriods) {
cout << period.first << "-" << period.second << " ";
}
cout << endl;
}
return 0;
}
33.项目排期【二分】
题解思路
将问题转化为,我们需要找到一个阈值k
(一个人的最大工作量),并将原数组nums
可以被分为N
部分(分配给N
个人),使得这N
部分的各自求和的最大值都不会超过k
(每个人各自的工作量不会超过k
)。
显然k
的选择是一个二段性问题:
- 当
k
非常小时,原数组nums
无论怎么分配都无法完成要求 - 当
k
非常大时,原数组nums
无论如何分配都可以完成要求 - 必然存在一个临界值
k
,使得存在nums
的分配结果恰好完成要求。
我们希望找到这个阈值k
,因此需要对k
进行二分查找,二分查找的范围为[max(nums), sum(nums)]
。当
k = max(nums)
时,能够被分为m = len(nums)
部分(需要m
个人来完成所有工作)k = sum(nums)
时,能够被分为1
部分(只由1
个人可以完成所有工作)
而上述二分过程的贪心子问题为:当我们选择了阈值k
时,数组nums
能否被分割不超过N
部分?
#include<bits/stdc++.h>
using namespace std;
// 当选择了阈值k时,如果m个任务nums可以被分配给N个员工,
// 且每一个员工的工作总量不超过k则返回True,否则返回False
// (注意此处nums必须是一个已排序好的逆序数组)
// 该子问题的时间复杂度与nums的长度m相关,为O(m^2)
bool subQuestion(int k, vector<int>& nums, int m, int N) {
int ans = 0;
// 初始化长度为m的check数组,用来表示第i个任务是否已经分配给了某一个员工
vector<int> check(m, 0);
// 遍历所有nums每一个工作量
for (int i = 0; i < m; i++) {
// 如果该工作已经由某个员工完成了,则直接跳过
if (check[i] == 1) continue;
// 否则,需要一个新的员工,来完成包含工作nums[i]在内的若干工作,故ans更新
ans++;
// 初始化当前员工所做的工作总量为0
int curSum = 0;
// 初始化变量j为i,用于:修改当前这个员工的工作情况
int j = i;
while (j < m) {
// 如果第j个工作已经安排,则j直接递增,跳过第j个工作
if (check[j] == 1) {
j++;
continue;
}
// 如果第j份工作和当前员工之前的工作量之和超过k,则这个员工不能选择这份工作,j递增
if (nums[j] + curSum > k) {
j++;
} else {
//如果第j份工作和当前员工之前的工作量之和不超过k
//则贪心地将这份工作安排给这个员工,修改cur_sum和check[j],j递增
curSum += nums[j];
check[j] = 1;
j++;
}
}
}
return ans <= N;
}
int main() {
vector<int> nums; // M个需求各自的工作量[天数]
string input;
getline(cin, input);
stringstream ss(input);
int num;
while (ss >> num) {
nums.push_back(num);
}
int m = nums.size();
// 输入员工人数N
int N;
cin >> N;
sort(nums.begin(), nums.end(), greater<int>()); //greater:由大变小
// 初始化左闭右开
int left = nums[0], right = accumulate(nums.begin(), nums.end(), 0) + 1;
while (left < right) {
int mid = left + (right - left) / 2;
// 如果选择了mid 作为阈值,可以将任务分配给N个人(组数小于等于N)
// 说明mid的选择偏大,区间应该左移,right左移
if (subQuestion(mid, nums, m, N)) {
right = mid;
} else {
left = mid + 1;
}
}
cout << left << endl;
return 0;
}
34.密码解密:字符串
#include<bits/stdc++.h>
using namespace std;
int main() {
// 定义字符串变量s,用于存储用户输入的密文
string s;
// 从标准输入读取一行数据存入s
getline(cin, s);
// 从26开始递减到1,创建映射并立即使用正则表达式进行全局替换
for (int i = 26; i >= 1; --i) {
// 构造映射的键:对于10到26,添加'*';否则使用数字本身
string key = to_string(i) + (i >= 10 ? "\\*" : "");
// 构造映射的值:ASCII码97对应'a',因此96+i对应的字符
char value = static_cast<char>(96 + i);
// 使用正则表达式和regex_replace方法,将密文中的每个加密字符(键)替换为对应的字母(值)
s = regex_replace(s, regex(key), string(1, value));
}
// 打印解密后的明文字符串
cout << s << endl;
// 主函数结束
return 0;
}
35.机场航班调度程序【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
vector<pair<string,string>> vi;
string buffer;
istringstream is(s);
while(getline(is,buffer,',')){
string name;
string num;
name = buffer.substr(0,2); //注意substr的用法!s.substr(pos,len);注意pos不能是iterator类型
num = buffer.substr(2,4);
vi.push_back(make_pair(name,num));
}
sort(vi.begin(),vi.end(),[](pair<string,string> p1,pair<string,string> p2){
if(p1.first == p2.first){
return p1.second<p2.second;
}else return p1.first<p2.first;
});
for(int i=0;i<vi.size();i++){
cout<<vi[i].first<<vi[i].second;
if(i!=vi.size()-1) cout<<',';
}
}
36.求幸存数之和:数组
#include<bits/stdc++.h>
using namespace std;
// 计算幸存数之和
int sumOfLeft(int nums[], int jump, int left, int length) {
// 如果幸存数量大于等于数组长度,则直接返回数组元素之和
if (left >= length) {
return accumulate(nums, nums + length, 0);
}
// 使用vector存储数组元素,方便删除操作
vector<int> lst(nums, nums + length);
// 初始化起跳点索引为0
int index = 0;
// 当列表大小大于幸存数量时,执行删除操作
while (lst.size() > left) {
// 计算下一个要删除元素的索引
index = (index + jump + 1) % lst.size();
// 删除计算出的索引处的元素
lst.erase(lst.begin() + index);
// 由于删除元素后,列表会缩短,下一个起跳点应当向前移动一位
index = index - 1 ;
}
// 计算并返回剩余元素之和
return accumulate(lst.begin(), lst.end(), 0);
}
int main() {
string line;
vector<int> nums;
int jump, left;
// 读取一行输入,按逗号分割,转换为整数数组
getline(cin, line);
stringstream ss(line);
string num;
while (getline(ss, num, ',')) {
nums.push_back(stoi(num));
}
// 读取跳数
cin >> jump;
// 读取幸存数量
cin >> left;
// 输出幸存数之和
cout << sumOfLeft(&nums[0], jump, left, nums.size()) << endl;
return 0;
}
37.结队编程【数组】
题解思路
考虑组合数学的方法。对于某一个元素nums[j]
,如果能够统计出其左边严格小于nums[j]
的元素的数量left_smaller[j]
和其右边严格大于nums[j]
的数量right_greater[j]
,那么以nums[j]
为中间第二个数,且满足nums[i] < nums[j] < nums[k]
的三元组(i, j, k)
的数量为left_smaller[j] * right_greater[j]
因此我们可以构建四个数组,left_greater
、left_smaller
、right_greater
、right_smaller
,这四个数组的长度均为n
。第j
个位置表示,位于j
的左边严格大于、位于j
的左边严格小于、位于j
的右边严格大于、位于j
的右边严格小于nums[j]
的元素个数。
C++
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> level(n);
for(int i=0;i<n;i++) cin>>level[i];
int res = 0;
for(int i=1;i<n-1;i++){
int ll = 0;
int lu = 0;
for(int j=0;j<i;j++){
if(level[j]<level[i]) ll++;
else if(level[j]>level[i]) lu++;
}
int rl = 0;
int ru = 0;
for(int k=i+1;k<n;k++){
if(level[k]<level[i]) rl++;
else if(level[k]>level[i]) ru++;
}
res+=(ll*ru+lu*rl);
}
cout<<res<<endl;
}
38.求字符串中所有整数的最小和
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
getline(cin, s);
bool flag = false;
int num = 0;
int ans = 0;
for (char ch : s) {
if (ch == '-') {
ans += num;
num = 0;
flag = true;
} else if (isdigit(ch)) {
if (flag) {
num = num * 10 - (ch - '0');
} else {
ans += (ch - '0');
}
} else {
ans += num;
num = 0;
flag = false;
}
}
ans += num;
cout << ans << endl;
return 0;
}
42.根据IP查找城市
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
#include <climits>
using namespace std;
// IP范围结构体
struct IpRange {
long start; // 起始IP的长整型数
long end; // 结束IP的长整型数
// 构造函数
IpRange(long s, long e) : start(s), end(e) {}
};
// 将字符串形式的IP地址转换为长整型数
long ipToLong(const string& ip) {
long result = 0;
istringstream ss(ip);
string block;
while (getline(ss, block, '.')) {
result = (result << 8) + stoi(block);
}
return result;
}
// 解析IP地址池字符串,返回城市名到IP范围列表的映射
map<string, vector<IpRange>> parseIpPool(const string& ipPool) {
map<string, vector<IpRange>> cityIpRanges;
istringstream ss(ipPool);
string cityRange;
while (getline(ss, cityRange, ';')) {
auto pos = cityRange.find('=');
string city = cityRange.substr(0, pos);
string ranges = cityRange.substr(pos + 1);
auto rangePos = ranges.find(',');
long start = ipToLong(ranges.substr(0, rangePos));
long end = ipToLong(ranges.substr(rangePos + 1));
cityIpRanges[city].emplace_back(start, end);
}
return cityIpRanges;
}
// 根据IP地址池和查询IP列表,返回最佳匹配城市列表的字符串
string matchCities(const string& ipPool, const string& queryIPs) {
auto cityIpRanges = parseIpPool(ipPool);
istringstream ss(queryIPs);
string ip;
string result;
while (getline(ss, ip, ',')) {
long ipNum = ipToLong(ip);
string bestMatchCity;
long smallestRange = LONG_MAX;
for (const auto& entry : cityIpRanges) {
for (const auto& range : entry.second) {
if (ipNum >= range.start && ipNum <= range.end) {
long rangeSize = range.end - range.start;
if (rangeSize < smallestRange) {
bestMatchCity = entry.first;
smallestRange = rangeSize;
}
}
}
}
result += bestMatchCity + ",";
}
if (!result.empty()) {
result.pop_back(); // 删除最后一个逗号
}
return result;
}
int main() {
string ipPool, queryIPs;
// 读取IP地址池和查询IP列表
getline(cin, ipPool);
getline(cin, queryIPs);
// 输出匹配的城市列表
cout << matchCities(ipPool, queryIPs) << endl;
return 0;
}
43.最长子字符串的长度(一):字符串
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int n = s.size();
int cnt = count(s.begin(),s.end(),'o');
cnt = cnt%2==0?cnt:cnt-1;
if(cnt == 0){
cout<<n;
return 0;
}
s+=s;
int l=0,r;
int res = 0;
int tmp_cnt = 0;
for(r=0;r<s.size();r++){
if(s[r] == 'o'){
tmp_cnt++;
}
while(tmp_cnt>cnt){
if(s[l] == 'o') tmp_cnt--;
l++;
}
int win = min(n,r-l+1);
if(tmp_cnt == cnt) res = max(res,win);
}
cout<<res;
}
44.会议室占用时间
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<vector<int>> intervals(n, vector<int>(2));
for (int i = 0; i < n; i++) {
cin >> intervals[i][0] >> intervals[i][1];
}
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
});
vector<vector<int>> ans;
ans.push_back(intervals[0]);
for (int i = 1; i < n; i++) {
vector<int>& lastInterval = ans.back();
vector<int>& currentInterval = intervals[i];
if (lastInterval[1] >= currentInterval[0]) {
lastInterval[1] = max(lastInterval[1], currentInterval[1]);
} else {
ans.push_back(currentInterval);
}
}
for (const auto& interval : ans) {
cout << interval[0] << " " << interval[1] << endl;
}
return 0;
}
45.悄悄话【DFS】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
vector<int> tree;
string buffer;
istringstream is(s);
while(getline(is,buffer,' ')){
tree.push_back(stoi(buffer));
}
for(int i=0;i<tree.size();i++){
if(tree[i]!=-1){
int fPos = (i-1)/2;
if(fPos>=0) tree[i]+=tree[fPos];
}
}
int res = -1;
for(int i=0;i<tree.size();i++) res = max(res,tree[i]);
cout<<res<<endl;
return 0;
}
46.分配土地【贪心】
#include<bits/stdc++.h>
using namespace std;
struct ST{
int x_l = -1;
int x_r = 501;
int y_h = 501;
int y_l = -1;
int cnt;
};
int main(){
int m,n;
cin>>m>>n;
vector<vector<int>> mp(m,vector<int>(n));
map<int,ST> dic;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>mp[i][j];
if(mp[i][j] == 0) continue;
dic[mp[i][j]].cnt++;
if(i>dic[mp[i][j]].x_r || dic[mp[i][j]].x_r == 501) dic[mp[i][j]].x_r = i;
if(i<dic[mp[i][j]].x_l || dic[mp[i][j]].x_l == -1) dic[mp[i][j]].x_l = i;
if(j>dic[mp[i][j]].y_h || dic[mp[i][j]].y_h == 501) dic[mp[i][j]].y_h = j;
if(j<dic[mp[i][j]].y_l || dic[mp[i][j]].y_l == -1) dic[mp[i][j]].y_l = j;
}
}
// for(auto x:dic){
// cout<<x.first<<' '<<x.second.x_l<<' '<< x.second.x_r<<' '<<x.second.y_h<<' '<<x.second.y_l<<endl;
// }
int res = 0;
for(auto x:dic){
if(x.second.cnt == 1){
res = max(res,1);
continue;
}
int chang = (x.second.x_r - x.second.x_l+1);
int kuan = (x.second.y_h - x.second.y_l+1);
res = max(res,chang*kuan);
}
cout<<res<<endl;
}
47.电脑病毒感染:广搜
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;
// 计算感染所有电脑所需的最少时间的函数
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
const int INF = INT_MAX / 2; // 定义无穷大的值,用于初始化距离数组
vector<int> dist(N, INF); // 存储从源电脑到其他所有电脑的最短感染时间
dist[K] = 0; // 源电脑的感染时间为0
// 使用Bellman-Ford算法更新所有电脑的最短感染时间
for (int i = 0; i < N; ++i) {
for (const auto& time : times) {
int u = time[0], v = time[1], w = time[2];
// 如果可以通过电脑u感染到电脑v,并且时间更短,则更新电脑v的感染时间
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
// 找出所有电脑中最长的感染时间
int maxWait = 0;
for (int i = 0; i < N; ++i) {
// 如果有电脑的感染时间仍为无穷大,表示该电脑不可被感染,返回-1
if (dist[i] == INF) return -1;
// 更新最长的感染时间
maxWait = max(maxWait, dist[i]);
}
// 返回感染所有电脑所需的最少时间
return maxWait;
}
int main() {
int N, connections;
cin >> N >> connections; // 电脑的数量和网络连接的数量
vector<vector<int>> times(connections, vector<int>(3)); // 存储每个连接和对应的感染时间
for (int i = 0; i < connections; ++i) {
// 读取每个连接的信息,将电脑编号减1转换为从0开始的索引
cin >> times[i][0] >> times[i][1] >> times[i][2];
times[i][0]--; // 感染源电脑编号
times[i][1]--; // 被感染电脑编号
}
int initial;
cin >> initial; // 初始被感染的电脑编号,转换为从0开始的索引
initial--;
// 输出感染所有电脑所需的最少时间
cout << networkDelayTime(times, N, initial) << endl;
return 0;
}
48.来自异国的客人【进制转换】
#include<bits/stdc++.h>
using namespace std;
int main(){
int k,n,m;
cin>>k>>n>>m;
string s = "";
while(k){
s = to_string(k%m) + s;
k/=m;
}
int res = 0;
for(auto c:s){
if(c-'0' == n) res++;
}
cout<<res;
}
51.小明找位置
//投机取巧法
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int num;
cin>>num;
string buffer;
istringstream is(s);
vector<int> stu;
while(getline(is,buffer,',')){
stu.push_back(stoi(buffer));
}
stu.push_back(num);
sort(stu.begin(),stu.end());
vector<int>::iterator first = stu.begin();
vector<int>::iterator it = find(stu.begin(),stu.end(),num);
cout<<distance(first,it)+1;
}
//二分法
int left = 0, right = nums.size();
while (left < right) {
int mid = left + (right - left) / 2; //防溢出
if (nums[mid] >= target) {
right = mid;
} else {
left = mid + 1;
}
}
52.素数之积【递归 循环 整数范围】
#include<bits/stdc++.h>
using namespace std;
int main(){
int num;
cin>>num;
vector<int> prime;
vector<bool> Num(num+1,false);
for(int i=2;i<num;i++){
if(Num[i] == false){
prime.push_back(i);
for(int j=i+i;j<num;j+=i){
Num[j] = true;
}
}
}
for(auto x:prime){
if(num%x == 0 && Num[num/x] == false){
cout<<x<<' '<<num/x<<endl;
return 0;
}
}
cout<<-1<<' '<<-1;
}
54.两个字符串间的最短路径问题【DP】
解题思路
每一个点(i, j)
可能可以从其左边(i, j-1)
,上边(i-1, j)
,左上(i-1, j-1)
转移过来。
其中i
和j
分别表示第一个字符串s1
和第二个字符串s2
中的第i
个和第j
个字符。
#include<bits/stdc++.h>
using namespace std;
int main() {
string s1, s2;
cin >> s1 >> s2;
int n = s1.length(); //列
int m = s2.length(); //行
// dp数组的初始化
// 构建大小为(m+1)*(n+1)的二维dp数组
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
//[0][0]-[i][0] 这一列初始化
for (int i = 1; i <= m; ++i) {
dp[i][0] = i;
}
//[0][0]-[0][j] 这一行初始化
for (int j = 1; j <= n; ++j) {
dp[0][j] = j;
}
// 双重遍历每一个点(i,j)
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
// 考察两个子串的最后一个字符s1[i-1]和s2[j-1]
// 若相等,则可以从左上角dp[i-1][j-1]转移过来
if (s1[j - 1] == s2[i - 1]) {
dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
}
// 若不相等,则只能从左边或者上边转移过来
else {
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1;
}
}
}
cout << dp[m][n] <<endl;
return 0;
}
55.执行时长:数组【B】
#include <iostream>
using namespace std;
int main() {
int maxTasks;
cin >> maxTasks;
int taskArrLen;
cin >> taskArrLen;
int* taskArr = new int[taskArrLen];
for (int i = 0; i < taskArrLen; i++) {
cin >> taskArr[i];
}
int currentTasks = 0;
int time = 0;
int index = 0;
while (currentTasks != 0 || index != taskArrLen) {
if (index < taskArrLen) {
currentTasks += taskArr[index];
index++;
}
currentTasks -= maxTasks;
if (currentTasks < 0) currentTasks = 0;
time++;
}
cout << time << endl;
delete[] taskArr;
return 0;
}
56.数组去重和排序【模拟,排序】
#include<bits/stdc++.h>
using namespace std;
struct ST{
int val;
int cnt;
int pos;
};
int main(){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
map<int,pair<int,int>> mp; //元素值,元素出现的次数,元素出现位置的相对顺序
int i = 0;
while(getline(is,buffer,',')){
//如果这个元素之前没有出现过,则记录下他元素出现位置的相对顺序
if(!mp.count(stoi(buffer))){
mp[stoi(buffer)].second = i++;
}
//累加该元素出现的次数
mp[stoi(buffer)].first++;
}
vector<ST> vi;
ST st;
for(auto x:mp){
st.val = x.first;
st.cnt = x.second.first;
st.pos = x.second.second;
vi.push_back(st);
}
sort(vi.begin(),vi.end(),[&](ST v1,ST v2){
if(v1.cnt == v2.cnt) return v1.pos<v2.pos;
else return v1.cnt>v2.cnt;
});
for(int i=0;i<vi.size();i++){
cout<<vi[i].val;
if(i<vi.size()-1) cout<<',';
}
}
57.测试用例执行计划【哈希】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int> v(n+1);
for(int i=1;i<=n;i++){
cin>>v[i];
}
vector<pair<int,int>> pri;
getchar();
for(int i=1;i<=m;i++){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
int tmp = 0;
while(getline(is,buffer,' ')){
tmp+=v[stoi(buffer)];
}
// cout<<tmp<<endl;
pri.push_back(make_pair(i,tmp));
}
sort(pri.begin(),pri.end(),[](pair<int,int> p1, pair<int,int> p2){
if(p1.second == p2.second){
return p1.first<p2.first;
}else return p1.second > p2.second;
});
for(auto x:pri){
cout<<x.first<<endl;
}
return 0;
}
58.5G网络建设
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> parents;
int find(int x) {
if (parents[x] != x) {
parents[x] = find(parents[x]);
}
return parents[x];
}
void unionSets(int x, int y) {
parents[find(x)] = find(y);
}
int main() {
int N, M;
cin >> N >> M;
parents.resize(N + 1);
for (int i = 1; i <= N; ++i) {
parents[i] = i;
}
int edge_num = 0;
vector<pair<int, pair<int, int>>> edges;
for (int i = 0; i < M; ++i) {
int X, Y, Z, P;
cin >> X >> Y >> Z >> P;
if (P == 1) {
if (find(X) == find(Y)) {
continue;
} else {
unionSets(X, Y);
edge_num++;
}
} else {
edges.push_back({Z, {X, Y}});
}
}
sort(edges.begin(), edges.end());
int ans = 0;
for (const auto& edge : edges) {
int Z = edge.first;
int X = edge.second.first;
int Y = edge.second.second;
if (find(X) != find(Y)) {
unionSets(X, Y);
ans += Z;
edge_num++;
if (edge_num == N - 1) {
break;
}
}
}
cout << (edge_num == N - 1 ? ans : -1) << endl;
return 0;
}
59.亲子游戏【BFS】
#include<bits/stdc++.h>
using namespace std;
int sx,sy;
int fx,fy;
int xx[]={0,0,1,-1},yy[]={1,-1,0,0};
int main(){
int n;
cin>>n;
vector<vector<int>> mp(n,vector<int>(n));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>mp[i][j];
if(mp[i][j] == -3){
sx = i;
sy = j;
}
if(mp[i][j] == -2){
fx = i;
fy = j;
}
}
}
vector<vector<int>> dp(n,vector<int>(n,0));
dp[sx][sy] = 0;
dp[fx][fy] = 0;
queue<pair<int,int>> q;
q.push({sx,sy});
mp[sx][sy] = -1;
int flag = 0;
while(!q.empty()){
int num = q.size();
while(num--){
auto t = q.front();
q.pop();
int x = t.first;
int y = t.second;
for(int i=0;i<4;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0&&dx<n&&dy>=0&&dy<n&&mp[dx][dy]!=-1){
if(dx == fx && dy == fy){
flag = 1;
mp[dx][dy] = 0;
}
dp[dx][dy] = max(dp[dx][dy],dp[x][y]+mp[dx][dy]);
q.push({dx,dy});
mp[dx][dy] = -1;
}
}
}
}
if(!flag){
cout<<-1;
return 0;
}
cout<<dp[fx][fy];
}
60.螺旋数字矩阵【模拟、数组】
解题思路
注意,本题和LeetCode54、螺旋矩阵非常类似。
本题既可以用迭代方法也可以用递归方法完成。本题解主要介绍递归方法。
题目要求矩阵列数尽可能少,很容易算出来最小的列数为c = ceil(n / m)
【一共有n
个数,最少有m
行】
注意到每次填充都优先填充矩阵的最外圈,比如对于5*5
的矩阵,初始化均用*
填充
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
假设需要填充21
个数,那么第一圈会螺旋式地填充如下
1 2 3 4 5
16 * * * 6
15 * * * 7
14 * * * 8
13 12 11 10 9
中间剩余一个(5-2)*(5-2) = 3*3
的未填充矩阵,那么可以从17
开始继续螺旋式地填充第二层矩阵,直到到达21
,即
1 2 3 4 5
16 17 18 19 6
15 * * 20 7
14 * * 21 8
13 12 11 10 9
显然每一次填充,都是从未填充矩阵的左上角开始填充其外层,直到填充完毕或到达规定数字。因此可以使用递归来完成上述过程。
C++
#include<bits/stdc++.h>
using namespace std;
// ans存储答案螺旋矩阵
// start_i, end_i, start_j, end_j分别为子矩阵的起始、终止的i和j下标
// cur_num为:未填充子矩阵左上角的第一个数
// n为终止数字
void padding(vector<vector<string>>& ans, int start_i, int end_i, int start_j, int end_j, int& cur_num, int n) {
//将最中间的数字填充上并退出递归即可
if (start_i == end_i && start_j == end_j) {
ans[start_i][start_j] = to_string(cur_num);
return;
}
// 未填充矩阵的上边界:从左往右,固定start_i,正序遍历j
for (int j = start_j; j <= end_j; j++) {
ans[start_i][j] = to_string(cur_num++);
if (cur_num > n) return;
}
// 未填充矩阵的右边界:从上往下,固定end_j,正序遍历i
for (int i = start_i + 1; i <= end_i; i++) {
ans[i][end_j] = to_string(cur_num++);
if (cur_num > n) return;
}
// 未填充矩阵的下边界:从右往左,固定end_i,逆序遍历j
for (int j = end_j - 1; j >= start_j; j--) {
ans[end_i][j] = to_string(cur_num++);
if (cur_num > n) return;
}
// 未填充矩阵的左边界:从下往上,固定start_j,逆序遍历i
for (int i = end_i - 1; i > start_i; i--) {
ans[i][start_j] = to_string(cur_num++);
if (cur_num > n) return;
}
// 对未填充数组进行递归
// start_i, end_i, start_j, end_j需要修改
padding(ans, start_i + 1, end_i - 1, start_j + 1, end_j - 1, cur_num, n);
}
int main() {
// 输入数字总数n,行数m
int n, m;
cin >> n >> m;
// 计算列数c,n除以m后向上取整
int c = ceil(double(n) / m);
//二维vector的初始化:行数是m,列数是c,且用"*"填充
vector<vector<string>> ans(m, vector<string>(c, "*"));
// cur_num为:未填充子矩阵左上角的第一个数
int cur_num = 1;
// start_i, end_i, start_j, end_j分别为子矩阵的起始、终止的i和j下标
// 分别传入0, m-1, 0, c-1
padding(ans, 0, m - 1, 0, c - 1, cur_num, n);
// 逐行输出螺旋矩阵
for (const auto& row : ans) {
for (const auto& elem : row) {
cout << elem << " ";
}
cout << endl;
}
return 0;
}
61.最大N个数与最小N个数的和【哈希】
#include<bits/stdc++.h>
using namespace std;
int main(){
int m;
cin>>m;
vector<int> num;
vector<int> newNum;
for(int i=0;i<m;i++){
int x;
cin>>x;
num.push_back(x);
}
sort(num.begin(),num.end());
for(int i=0;i<num.size()-1;i++){
if(num[i]!=num[i+1]) newNum.push_back(num[i]);
}
newNum.push_back(num[num.size()-1]);
int len = newNum.size();
int n;
cin>>n;
int res = 0;
int i,j;
for(i=0,j=len-1;i<n && j>len-1-n && i<j;i++,j--){
res+=(newNum[i]+newNum[j]);
}
if(2*n>len){
cout<<-1;
return 0;
}
cout<<res<<endl;
}
62.火星文计算2【字符串、单调栈】
#include<bits/stdc++.h>
using namespace std;
stack<int> st_num;
stack<char> st_op;
map<char,int> mp={{'$',1},{'#',2}};
void eval(){
int y = st_num.top();
st_num.pop();
int x = st_num.top();
st_num.pop();
char c = st_op.top();
st_op.pop();
if(c == '#'){
int num = 4*x+3*y+2;
st_num.push(num);
}else if(c == '$'){
int num = 2*x+y+3;
st_num.push(num);
}
}
int main(){
string s;
getline(cin,s);
for(int i=0;i<s.size();i++){
if(isdigit(s[i])){
int j = i,oper = 0;
while(j<s.size() && isdigit(s[j])){
oper = oper*10+s[j]-'0';
j++;
}
i = j-1;
st_num.push(oper);
}else{
while(st_op.size() && mp[st_op.top()]>=mp[s[i]]) eval();
st_op.push(s[i]);
}
}
while(st_op.size()) eval();
cout<<st_num.top()<<endl;
return 0;
}
出现频率一次:
67.田忌赛马: 编程基础
#include<bits/stdc++.h>
using namespace std;
int maxWin = 0;
int res = 0;
void dfs(vector<int> a,vector<int> b,int id_b, int n,int winNum,vector<bool>& vis){
// 计算没有访问过的马
int notVis = 0;
for(auto b:vis){
if(!b) notVis++;
}
// 如果 已经赢的场数 + 没有上场的马的个数 < 最优结果的赢的场数
// 则 说明这次排列不能到达最优的结果,剪枝
if(maxWin > winNum + notVis) return;
// 如果此次排列已经达到最优的结果
// 则未上场的马无论如何排列都能满足最优【阶乘】
if(winNum == maxWin){
int oper = 1;
for(int i=1;i<=notVis;i++){
oper*=i;
}
res+=oper;
return;
}
for(int id_a = 0;id_a<n;id_a++){
if(!vis[id_a]){
vis[id_a] = true;
dfs(a,b,id_b+1,n,winNum+(a[id_a] > b[id_b] ? 1 : 0),vis);
vis[id_a] = false;
}
}
}
int main(){
vector<int> a;
vector<int> b;
string s_a;
getline(cin,s_a);
string buffer_a;
istringstream is_a(s_a);
while(getline(is_a,buffer_a,' ')){
a.push_back(stoi(buffer_a));
}
string s_b;
getline(cin,s_b);
string buffer_b;
istringstream is_b(s_b);
while(getline(is_b,buffer_b,' ')){
b.push_back(stoi(buffer_b));
}
sort(a.begin(),a.end(),greater<int>());
sort(b.begin(),b.end(),greater<int>());
int n = a.size();
vector<bool> vis(n,false);
//先判断最多有几组能赢
int id_a = 0,id_b = 0;
while(id_b<n){
if(a[id_a]>b[id_b]){
id_a++;
id_b++;
maxWin++;
}else{
id_b++;
}
}
if(maxWin == 0){
cout<<res<<endl;
return 0;
}else{
dfs(a,b,0,n,0,vis);
cout<<res<<endl;
}
}
68.单词接龙【B】
#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int startIdx;
cin >> startIdx;
int n;
cin >> n;
cin.ignore();
unordered_map<char, vector<string>> dic;
string ans = "";
for (int i = 0; i < n; i++) {
string word;
getline(cin, word);
if (i == startIdx) {
ans += word;
} else {
char firstCh = word[0];
dic[firstCh].push_back(word);
}
}
for (auto& entry : dic) {
sort(entry.second.begin(), entry.second.end(), [](const string& a, const string& b) {
if (a.length() != b.length()) {
return a.length() < b.length();
} else {
return a > b;
}
});
}
while (!dic[ans.back()].empty()) {
string followingWord = dic[ans.back()].back();
dic[ans.back()].pop_back();
ans += followingWord;
}
cout << ans << endl;
return 0;
}
69.五子棋迷【B】
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
// Function to find how many consecutive 'color' elements are in front of 'i' in 'nums'
int findFront(int color, int i, vector<int>& nums) {
int ans = 0;
i = i - 1;
while (i >= 0 && nums[i] == color) {
ans++;
i--;
}
return ans;
}
// Function to find how many consecutive 'color' elements are after 'i' in 'nums'
int findBack(int color, int i, vector<int>& nums) {
int ans = 0;
i = i + 1;
while (i < nums.size() && nums[i] == color) {
ans++;
i++;
}
return ans;
}
int main() {
int color;
cin >> color;
vector<int> nums;
int num;
while (cin >> num) {
nums.push_back(num);
}
int n = nums.size();
int maxLength = 0;
int ans = -1;
for (int i = 0; i < n; i++) {
if (nums[i] == 0) {
int curNum = 1 + findFront(color, i, nums) + findBack(color, i, nums);
if (curNum <= 5) {
if (curNum > maxLength) {
ans = i;
maxLength = curNum;
} else if (curNum == maxLength) {
if (abs(i - n / 2) < abs(ans - n / 2)) {
ans = i;
}
}
}
}
}
cout << ans << endl;
return 0;
}
70.找出两个整数数组中同时出现的整数【B】
from collections import defaultdict, Counter
nums1 = list(map(int, input().split(",")))
nums2 = list(map(int, input().split(",")))
# 使用计数器Counter,分别统计nums1和nums2元素出现频率
cnt1 = Counter(nums1)
cnt2 = Counter(nums2)
# 初始化哈希表cnt_both,用来记录同时在nums1和nums2中出现的元素
cnt_both = Counter()
# 遍历cnt1中的所有数字
for num in cnt1:
# 如果num也在cnt2中存在
if num in cnt2:
# 同时出现的次数,取较小值,储存在cnt_both中
cnt_both[num] = min(cnt1[num], cnt2[num])
# 构建一个新的哈希表,用于储存共同出现频率为freq的所有数字构成的列表
ans = defaultdict(list)
# 遍历cnt_both中的所有键值对,储存在ans中
for num, freq in cnt_both.items():
ans[freq].append(num)
# 如果此时ans的长度为0,则输出"NULL"
if len(ans) == 0:
print("NULL")
# 否则输出各行的结果
else:
# 对ans中的所有频率freq进行排序后遍历
for freq in sorted(ans.keys()):
# 获得freq对应的数字列表,然后再次排序
nums_with_freq = list(sorted(ans[freq]))
# 输出freq对应的已排序的数字列表
print("{}:{}".format(freq, ",".join(str(item) for item in nums_with_freq)))
71、Wonderland
#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std;
// 将输入的字符串转换为整数数组
vector<int> split(const string &s, char delim) {
stringstream ss(s);
string item;
vector<int> tokens;
while (getline(ss, item, delim)) {
tokens.push_back(stoi(item));
}
return tokens;
}
int mincostTickets(vector<int> &costs, vector<int> &days) {
// 找到days数组中的最大值,确定旅游的最后一天
int maxDay = *max_element(days.begin(), days.end());
// 创建一个长度为maxDay+1的布尔数组,用于标记每一天是否需要游玩
vector<bool> travelDays(maxDay + 1, false);
for (int day : days) {
travelDays[day] = true;
}
// 创建一个长度为maxDay+1的整数数组,用于保存每一天的最低消费
vector<int> dp(maxDay + 1, 0);
for (int i = 1; i <= maxDay; i++) {
// 如果这一天不需要游玩,那么这一天的最低消费就和前一天的最低消费相同
if (!travelDays[i]) {
dp[i] = dp[i - 1];
continue;
}
// 计算购买各种票后的消费
int cost1 = dp[max(0, i - 1)] + costs[0]; // 购买1天的票
int cost3 = dp[max(0, i - 3)] + costs[1]; // 购买3天的票
int cost7 = dp[max(0, i - 7)] + costs[2]; // 购买7天的票
int cost30 = dp[max(0, i - 30)] + costs[3]; // 购买30天的票
// 这一天的最低消费就是购买各种票后消费的最小值
dp[i] = min({cost1, cost3, cost7, cost30});
}
// 返回最后一天的最低消费,即为完成整个游玩计划的最低消费
return dp[maxDay];
}
int main() {
string costsStr, daysStr;
getline(cin, costsStr);
getline(cin, daysStr);
vector<int> costs = split(costsStr, ' ');
vector<int> days = split(daysStr, ' ');
cout << mincostTickets(costs, days) << endl;
return 0;
}
73.任务处理【贪心】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<pair<int,int>> v;
int x,y;
while(cin>>x>>y){
v.push_back({x,y});
}
sort(v.begin(),v.end(),[](pair<int,int> p1, pair<int,int> p2){
if(p1.second == p2.second){
return p1.first>p2.first;
}else return p1.second > p2.second;
});
int res = 0;
int s = 0;
int time = v[0].second;
for(int i=time;i>=1;i--){
if(i>=v[s].first && i<=v[s].second){
res++;
s++;
}
}
cout<<res<<endl;
return 0;
}
75.计算三叉搜索树的高度
#include <iostream>
#include <vector>
using namespace std;
struct Node {
int val;
Node* left;
Node* mid;
Node* right;
Node(int val) : val(val), left(nullptr), mid(nullptr), right(nullptr) {}
};
int ans = 1;
void dfs(Node* curNode, int val, int curDepth) {
if (val - curNode->val < -500) {
if (curNode->left == nullptr) {
curNode->left = new Node(val);
ans = max(ans, curDepth + 1);
return;
}
dfs(curNode->left, val, curDepth + 1);
} else if (val - curNode->val > 500) {
if (curNode->right == nullptr) {
curNode->right = new Node(val);
ans = max(ans, curDepth + 1);
return;
}
dfs(curNode->right, val, curDepth + 1);
} else {
if (curNode->mid == nullptr) {
curNode->mid = new Node(val);
ans = max(ans, curDepth + 1);
return;
}
dfs(curNode->mid, val, curDepth + 1);
}
}
int main() {
int n;
cin >> n;
vector<int> vals(n);
for (int i = 0; i < n; i++) {
cin >> vals[i];
}
Node* root = new Node(vals[0]);
for (int i = 1; i < n; i++) {
dfs(root, vals[i], 1);
}
cout << ans << endl;
return 0;
}
76.攀登者1: 【模拟、数组】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
vector<int> vi;
string buffer;
istringstream is(s);
while(getline(is,buffer,',')){
vi.push_back(stoi(buffer));
}
int res = 0;
for(int i=0;i<vi.size();i++){
if(i == 0 && vi[i+1]<vi[i]) res++;
else if(i == vi.size()-1 && vi[i]>vi[i-1]) res++;
else if(i>0 && i<vi.size()-1 && vi[i]>vi[i-1] && vi[i]>vi[i+1]) res++;
}
cout<<res<<endl;
}
78.多段线数据压缩【数组 栈 递归 矩阵 循环】
解题思路
本题的核心在于如何判定三点共线。
已知三个点A
、B
、C
坐标分别为(x1, y1)
、(x2, y2)
、(x3, y3)
,那么向量AB
和AC
分别可以用(x2-x1, y2-y1)
以及(x3-x1, y3-y1)
来表示。
三点共线等价于这两个向量平行,即等价于(x2-x1)*(y3-y1) == (x3-x1)*(y2-y1)
成立。
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<pair<int,int>> vi;
vector<pair<int,int>> res;
int x,y;
while(cin>>x>>y){
vi.push_back(make_pair(x,y));
}
for(int i=0;i<vi.size();i++){
if(i == 0) res.push_back(vi[i]);
else if(i == vi.size()-1) res.push_back(vi[i]);
else{
if((vi[i+1].first - vi[i].first)*(vi[i+1].second-vi[i-1].second) == (vi[i+1].first - vi[i-1].first)*(vi[i+1].second-vi[i].second)){
continue;
}else res.push_back(vi[i]);
}
}
for(auto x:res) cout<<x.first<<' '<<x.second<<' ';
}
79.文件缓存系统
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
struct File {
int access_count;
int last_access_time;
int size;
};
int main() {
int maxSize, N;
cin >> maxSize >> N;
unordered_map<string, File> dic;
int curSize = 0;
for (int time = 0; time < N; ++time) {
string op;
cin >> op;
if (op == "put") {
string fileName;
int fileSize;
cin >> fileName >> fileSize;
if (dic.find(fileName) != dic.end() || fileSize > maxSize) {
continue;
}
while (maxSize - curSize < fileSize) {
auto it = min_element(dic.begin(), dic.end(), [](const auto& a, const auto& b) {
return a.second.access_count == b.second.access_count ? a.second.last_access_time < b.second.last_access_time
: a.second.access_count < b.second.access_count;
});
curSize -= it->second.size;
dic.erase(it);
}
dic[fileName] = {0, time, fileSize};
curSize += fileSize;
} else if (op == "get") {
string fileName;
cin >> fileName;
auto it = dic.find(fileName);
if (it != dic.end()) {
it->second.access_count++;
}
}
}
vector<string> ans;
for (const auto& entry : dic) {
ans.push_back(entry.first);
}
sort(ans.begin(), ans.end());
if (ans.empty()) {
cout << "NONE" << endl;
} else {
for (size_t i = 0; i < ans.size() - 1; ++i) {
cout << ans[i] << ",";
}
cout << ans.back() << endl;
}
return 0;
}
82.启动多任务排序
#include<bits/stdc++.h>
using namespace std;
// 一个任务如果没有依赖的任务,则立刻开始执行
// 如果同时有多个任务要执行,则根据任务名称字母顺序排序。
// 输出为排序后的启动任务列表,多个任务之间用单个空格分割
struct ST{
string dot;
int level;
// 重载 < 就是重写 sort 的规则
bool operator<(const ST& other) const{
if(level == other.level){ //如果这两个任务可以同时执行,则按字母顺序执行
return other.dot < dot;
}else { // 否则按拓扑序列执行
return other.level < level;
}
}
};
int main(){
string s;
getline(cin,s);
istringstream is(s);
string buffer;
map<string,set<string>> mp;
map<string,int> cnt;
set<string> st;
while(is>>buffer){
int pos = buffer.find("->");
string e = buffer.substr(0,pos);
string f = buffer.substr(pos+2);
// 构造邻接表,表内按字典序排列
mp[f].insert(e);
// 按字典序存储顶点
st.insert(f);
st.insert(e);
// 记录点的入度
cnt[e]++;
}
priority_queue<ST> q;
//存储入度为 0 的点
for(auto dot:st){
if(cnt.count(dot) == 0) q.push({dot,0});
}
vector<string> res;
int level = 0;
while(!q.empty()){
int num = q.size();
level++;
while(num--){
auto t = q.top();
q.pop();
res.push_back(t.dot);
for(auto x:mp[t.dot]){
cnt[x]--;
if(cnt[x] == 0) q.push({x,level});
}
}
}
for(auto task:res) cout<<task<<' ';
}
83.推荐多样性:字符串 滑窗
#include <iostream>
#include <vector>
#include <queue>
#include <sstream>
#include <string>
using namespace std;
int main() {
int numberOfRows, numberOfColumns;
cin >> numberOfRows >> numberOfColumns;
cin.ignore(); // 忽略换行符
vector<queue<int>> queueList;
string inputLine;
// 循环读取输入,每次读取一行,直到输入结束
while (getline(cin, inputLine) && !inputLine.empty()) {
istringstream iss(inputLine);
queue<int> numberQueue;
int number;
// 将一行中的数分割并加入到队列中
while (iss >> number) {
numberQueue.push(number);
}
queueList.push_back(numberQueue);
}
vector<int> matrix(numberOfColumns * numberOfRows, 0);
int matrixIndex = 0;
int queueIndex = 0;
// 循环,直到所有元素被分配完毕
while (matrixIndex < matrix.size()) {
bool didRemoveQueue = false;
for (int i = 0; i < numberOfRows && !queueList.empty(); ++i) {
if (queueList[queueIndex].empty()) {
queueList.erase(queueList.begin() + queueIndex);
if (queueList.empty()) break;
queueIndex %= queueList.size();
didRemoveQueue = true;
}
if (!queueList[queueIndex].empty()) {
matrix[matrixIndex++] = queueList[queueIndex].front();
queueList[queueIndex].pop();
if (matrixIndex >= matrix.size()) break;
}
}
if (!didRemoveQueue && !queueList.empty()) {
queueIndex = (queueIndex + 1) % queueList.size();
}
}
// 按顺序输出结果
for (int row = 0; row < numberOfRows; ++row) {
for (int col = 0; col < numberOfColumns; ++col) {
cout << matrix[col * numberOfRows + row] << " ";
}
}
return 0;
}
86.跳马问题【BFS】
#include<bits/stdc++.h>
using namespace std;
//请问能否将棋盘上所有的马移动到同一个位置
//若可以请输出移动的最小步数。若不可以输出 0。
int xx[]={1,1,2,2,-1,-1,-2,-2};
int yy[]={-2,2,-1,1,-2,2,-1,1};
vector<vector<int>> bfs(int i, int j, int m, int n, int step) {
//对 mat 进行初始化:-1 代表这个点无法到达【或没有访问过】
vector<vector<int>> mat(m, vector<int>(n, -1));
mat[i][j] = 0;
queue<pair<int, int>> q;
q.push({i, j});
int level = 0;
while (!q.empty()) {
// 记录当前已经走的步数
level++;
// 如果已经走的步数比能走的步数长,则退出
if (level > step) {
break;
}
int num = q.size();
while(num--){
auto t = q.front();
q.pop();
int x = t.first;
int y = t.second;
for (int i=0;i<8;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if (dx>=0&&dx<m&&dy>=0&&dy<n&&mat[dx][dy] == -1) {
mat[dx][dy] = level;
q.push({dx, dy});
}
}
}
}
return mat;
}
int main(){
int m, n;
cin >> m >> n;
getchar();
// 输入棋盘内的数据
vector<vector<string>> mp(m, vector<string>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cin >> mp[i][j];
}
}
vector<vector<int>> resMat(m, vector<int>(n, 0)); //存储最终的 mat:多个马的 mat 的叠加
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 当棋盘上是马
if (mp[i][j] != ".") {
// 计算出该匹马能够到达地图上某个点的最小步数
auto mat = bfs(i, j, m, n, stoi(mp[i][j])); //mat:vector<vector<int>>
// 每计算出一匹马的 mat 就进行一次对 resMat 的更新
for (int x = 0; x < m; x++) {
for (int y = 0; y < n; y++) {
//只要有一匹马无法到达该点,则不满足题设要求,后续这个点也不会满足
if (mat[x][y] == -1 || resMat[x][y] == -1) {
resMat[x][y] = -1;
} else {
// 更新能移动到该点的所有马的总步数
resMat[x][y] += mat[x][y];
}
}
}
}
}
}
int res = INT_MAX;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
//更新要移动的最小步数
if (resMat[i][j] != -1 && res > resMat[i][j]) {
res = resMat[i][j];
}
}
}
cout << ((res == INT_MAX) ? 0 : res) << endl;
return 0;
}
87.矩阵匹配: 二分查找 DFS搜索
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
int n, m, k; // n、m、k 分别表示矩阵的行数、列数和要求的第K大数
vector<vector<int>> matrix; // matrix 用于存储输入的矩阵
vector<int> match; // match 数组用于存储匹配信息,match[j] = i 表示第j列与第i行匹配
vector<bool> vis; // vis 数组用于标记每一列在当前增广路中是否被访问过
// 深度优先搜索寻找增广路径
bool dfs(int i, int currentVal) {
for (int j = 0; j < m; j++) {
// 检查列j是否未被访问过且第i行第j列的值小于等于currentVal
if (!vis[j] && matrix[i][j] <= currentVal) {
vis[j] = true; // 标记列j为已访问
// 如果列j未匹配或者列j的匹配行可以匹配到其他列
if (match[j] == -1 || dfs(match[j], currentVal)) {
match[j] = i; // 将列j与行i匹配
return true; // 找到增广路径
}
}
}
return false; // 没有找到增广路径
}
// 检查当前值是否满足条件
bool check(int currentVal) {
match.assign(m, -1); // 初始化匹配数组
vis.assign(m, false); // 初始化访问标记数组
int smallerCount = 0; // 统计满足条件的数量
for (int i = 0; i < n; i++) {
fill(vis.begin(), vis.end(), false); // 每次搜索前重置访问标记
if (dfs(i, currentVal)) {
smallerCount++; // 如果找到增广路径,则计数增加
}
}
return smallerCount >= n - k + 1; // 检查是否有足够的小于等于currentVal的数
}
int main() {
cin >> n >> m >> k; // 读取行数、列数和k值
int min = 1, maxT = INT_MIN; // 初始化二分查找的上下界
matrix.assign(n, vector<int>(m)); // 初始化矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> matrix[i][j]; // 读取矩阵元素
maxT = max(maxT, matrix[i][j]); // 更新矩阵元素的最大值,作为二分查找的上界
}
}
// 二分查找确定第K大的数的最小可能值
while (min <= maxT) {
int mid = (min + maxT) / 2; // 取中间值
if (check(mid)) {
maxT = mid - 1; // 如果当前中间值满足条件,则尝试寻找更小的值
} else {
min = mid + 1; // 如果不满足条件,则尝试寻找更大的值
}
}
cout << min << endl; // 输出最终结果
return 0;
}
89.伐木工【贪心】
规律
- 尽量分成长度为
3
的小段,这样才能使得乘积的收益尽可能大。 - 当
X <= 4
时,不进行切割。注意4
不会被切割为2 2
,因为虽然2 2
也能得到4
的总收益,但是并不是切割数最小的方式 - 当
X > 4
且X % 3 == 0
时,分成n // 3
组长度为3
的小段。 - 当
X > 4
且X % 3 == 2
时,分成n // 3
组长度为3
的小段,1
组长度为2
的小段。 - 当
X > 4
且X % 3 == 1
时,分成n // 3 - 1
组长度为3
的小段,1
组长度为4
的小段。
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> res;
int x;
cin>>x;
if(x<=4){
cout<<x<<endl;
return 0;
}
while(x-3>1){
res.push_back(3);
x-=3;
}
if(x<=4&&x>0){
res.push_back(x);
}
sort(res.begin(),res.end());
for(auto x : res) cout<<x<<' ';
}
90.园区参观路径
//DFS写法
#include<bits/stdc++.h>
using namespace std;
int sx,sy,fx,fy,c,k;
bool vis[105][105];
bool mp[105][105];
int x[] = {0,1};
int y[] = {1,0};
int res = 0;
void dfs(int sx,int sy){
if(sx == fx&&sy == fy){
res++;
return;
}
for(int i=0;i<2;i++){
int dx = sx + x[i];
int dy = sy + y[i];
if(!vis[dx][dy]&&dx>=1&&dx<=k&&dy>=1&&dy<=c&&!mp[dx][dy]){
vis[dx][dy] = 1;
dfs(dx,dy);
vis[dx][dy] = 0;
}
}
}
int main(){
cin>>c>>k;
fx = k, fy = c;
for(int i=1;i<=k;i++){
for(int j=1;j<=c;j++){
int x;
cin>>x;
mp[i][j] = x;
}
}
vis[1][1] = 1;
sx = 1,sy = 1;
dfs(sx,sy);
cout<<res<<endl;
return 0;
}
//DP写法
#include<bits/stdc++.h>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
vector<vector<int>> mp(m+2,vector<int>(n+2));
vector<vector<int>> dp(m+2,vector<int>(n+2));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cin>>mp[i][j];
}
}
dp[1][1] = 1;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(mp[i][j] == 0 && dp[i][j] == 0){
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
}
cout<<dp[m][n];
}
91.最小矩阵宽度【不定滑窗】
#include<bits/stdc++.h>
using namespace std;
bool check(unordered_map<int, int>& countMap, unordered_map<int, int>& windowCountMap) {
for (auto& entry : countMap) {
int key = entry.first;
int value = entry.second;
if (windowCountMap[key] < value) {
return false;
}
}
return true;
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> mat(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> mat[i][j];
}
}
int k;
cin >> k;
vector<int> nums(k);
for (int i = 0; i < k; i++) {
cin >> nums[i]; //需要包含的数
}
// 每一列的映射表初始化
vector<unordered_map<int, int>> colContainsList(m);
for (int i = 0; i < m; i++) {
colContainsList[i] = unordered_map<int, int>();
}
// 将每一列包含的数及其个数记录到映射表中
for (int j = 0; j < m; j++) {
for (int i = 0; i < n; i++) {
int val = mat[i][j];
colContainsList[j][val]++;
}
}
unordered_map<int, int> countMap;
for (int num : nums) {
countMap[num]++; //计算需要包含的每个数的个数
}
unordered_map<int, int> windowCountMap;
int answer = INT_MAX;
int left = 0;
for (int right = 0; right < m; right++) {
//将第right列各个元素出现的个数,加入到用于储存窗口中的元素以及其个数的哈希表windowCountMap中
for (auto& entry : colContainsList[right]) {
int key = entry.first;
int value = entry.second;
windowCountMap[key] += value;
}
while (check(countMap, windowCountMap)) { //检查windowCountMap是否完全包含需要的数组
answer = min(answer, right - left + 1); //满足要求时,更新答案
for (auto& entry : colContainsList[left]) { //最左列向右移动
int key = entry.first;
int value = entry.second;
windowCountMap[key] -= value;
}
left++;
}
}
cout << (answer != INT_MAX ? answer : -1) << endl;
return 0;
}
92.机器人仓库搬砖: 二分查找 字符串 编程基础 数组
#include<bits/stdc++.h>
using namespace std;
int minEnergyBlocks(vector<int>& bricks, int hours) {
if (bricks.size() > 8) { // 如果砖块数量大于8
return -1; // 返回-1
}
int left = 1, right = *max_element(bricks.begin(), bricks.end()); // 初始化左右边界
while (left < right) { // 二分查找
int middle = (left + right) / 2; // 取中间值
int total_time = 0; // 计算当前能量块数量下能够搬完所有砖的总时间
for (int i = 0; i < bricks.size(); i++) {
total_time += ceil((double)bricks[i] / middle);
}
if (total_time > hours) { // 如果当前能量块数量下搬完所有砖的总时间超过了限定时间,缩小搜索范围
left = middle + 1;
} else { // 否则,减小能量块数量
right = middle;
}
}
int sum = 0;
for (int i = 0; i < bricks.size(); i++) {
sum += ceil((double)bricks[i] / left);
}
if (sum > hours) { // 检查最终确定的能量块数量是否能在规定时间内搬完所有砖
return -1; // 无法在规定时间内搬完所有砖
}
return left; // 返回最小能量块数量
}
int main() {
vector<int> bricks;
int brick;
while (cin >> brick) {
bricks.push_back(brick);
}
cout << minEnergyBlocks(bricks, 8); // 调用函数并输出结果
return 0;
}
93.密码输入检测
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
stack<char> st;
int lower = 0, upper = 0, digit = 0, cnt = 0;
for(int i=0;i<s.size();i++){
if(s[i]!='<'){
st.push(s[i]);
} else if(s[i] == '<'){
if(!st.empty()){
st.pop();
}else{
continue;
}
}
}
string res = "";
int len = st.size();
while(!st.empty()){
if(islower(st.top())) lower++;
if(isupper(st.top())) upper++;
if(isdigit(st.top())) digit++;
if(!isalnum(st.top())&&!isspace(st.top())) cnt++;
res = st.top()+res;
st.pop();
}
int flag = 1;
if(len<8||lower<1||upper<1||cnt<1) flag = 0;
if(flag){
cout<<res<<','<<"true"<<endl;
}else{
cout<<res<<','<<"false"<<endl;
}
}
95.考勤信息: 字符串
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 定义一个函数用于判断是否能获得考勤奖
bool can_receive_award(const vector<string>& records) {
int absent_count = 0; // 用于记录缺勤的次数
for (size_t i = 0; i < records.size(); ++i) { // 遍历考勤记录
if (records[i] == "absent") { // 如果记录为缺勤
++absent_count; // 缺勤次数加1
if (absent_count > 1) return false; // 如果缺勤超过1次,返回false
}
if (records[i] == "late" || records[i] == "leaveearly") { // 如果记录为迟到或早退
// 如果前一天也是迟到或早退,则不能获得考勤奖
if (i > 0 && (records[i - 1] == "late" || records[i - 1] == "leaveearly")) {
return false;
}
}
if (i >= 6) { // 如果记录长度大于等于7,检查任意连续7天的考勤记录
int count_in_7_days = 0; // 计算连续7天内非出勤的天数
for (int j = i - 6; j <= i; ++j) {
if (records[j] != "present") ++count_in_7_days;
}
if (count_in_7_days > 3) return false; // 如果连续7天内非出勤天数超过3天,返回false
}
}
return true; // 所有条件都满足,返回true
}
int main() {
int test_cases;
cin >> test_cases; // 读取测试用例的数量
cin.ignore(); // 忽略换行符
for (int i = 0; i < test_cases; ++i) {
string line;
getline(cin, line); // 读取一行考勤记录
vector<string> records;
size_t pos = 0;
while ((pos = line.find(' ')) != string::npos) {
records.push_back(line.substr(0, pos));
line.erase(0, pos + 1);
}
records.push_back(line); // 添加最后一个记录
cout << (can_receive_award(records) ? "true" : "false") << " ";
}
cout << endl;
return 0;
}
97.数据单元的变量替换:字符串 编程基础
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// 全局变量,用于存储单元格的值、标记单元格是否正在处理中以及是否已处理完成
vector<string> cellValues;
vector<bool> isProcessing;
vector<bool> hasProcessed;
// 定义processCell函数,用于处理单元格内的数据,包括处理引用和检测循环引用
bool processCell(int cellIndex) {
// 如果该单元格已处理过,直接返回true
if (hasProcessed[cellIndex]) return true;
// 如果该单元格正在处理中,则存在循环引用,返回false
if (isProcessing[cellIndex]) return false;
// 标记该单元格为正在处理状态
isProcessing[cellIndex] = true;
ostringstream processedValue; // 创建一个字符串流,用于拼接处理后的单元格值
string currentCellValue = cellValues[cellIndex]; // 获取当前单元格的值
int cellLength = currentCellValue.length(); // 获取单元格值的长度
// 遍历单元格值中的每个字符
for (int charIndex = 0; charIndex < cellLength; ) {
// 如果检测到引用格式(例如<A>)
if (currentCellValue[charIndex] == '<' && charIndex + 2 < cellLength && currentCellValue[charIndex + 2] == '>') {
char referencedCellId = currentCellValue[charIndex + 1]; // 获取被引用的单元格标识符
int referencedIndex = referencedCellId - 'A'; // 将单元格标识符转换为索引
// 检查引用的有效性
if (referencedCellId < 'A' || referencedCellId > 'Z' || referencedIndex == cellIndex || referencedIndex >= cellValues.size() || !processCell(referencedIndex)) {
return false;
}
// 将引用的单元格值添加到处理后的值中
processedValue << cellValues[referencedIndex];
charIndex += 3; // 跳过引用格式,继续处理下一个字符
} else {
// 如果当前字符不是引用格式,直接添加到处理后的值中
processedValue << currentCellValue[charIndex];
charIndex++; // 移动到下一个字符
}
}
// 更新当前单元格的值为处理后的值
cellValues[cellIndex] = processedValue.str();
// 标记该单元格为不再处理中
isProcessing[cellIndex] = false;
// 标记该单元格为已处理完成
hasProcessed[cellIndex] = true;
// 检查处理后的单元格值是否超过100个字符或包含非字母数字字符
if (cellValues[cellIndex].length() > 100 || !all_of(cellValues[cellIndex].begin(), cellValues[cellIndex].end(), [](char c) {
return isalnum(c); // 检查字符是否为字母或数字
})) {
return false;
}
return true; // 返回处理成功
}
int main() {
string line;
getline(cin, line); // 从标准输入读取一行数据
istringstream input(line); // 使用字符串流解析读取的数据
string cell;
// 使用逗号分隔符读取单元格值,并添加到cellValues向量中
while (getline(input, cell, ',')) {
cellValues.push_back(cell);
}
// 如果单元格数量超过26个,输出-1并结束程序
if (cellValues.size() > 26) {
cout << "-1" << endl;
return 0;
}
// 初始化isProcessing和hasProcessed向量的大小和初始值
isProcessing.resize(cellValues.size(), false);
hasProcessed.resize(cellValues.size(), false);
ostringstream result; // 创建一个字符串流
// 用于存储最终结果
for (int cellIndex = 0; cellIndex < cellValues.size(); cellIndex++) {
// 处理每个单元格,如果处理失败则输出-1并结束程序
if (!processCell(cellIndex)) {
cout << "-1" << endl;
return 0;
}
// 在结果中添加处理后的单元格值,单元格之间用逗号分隔
if (cellIndex > 0) result << ",";
result << cellValues[cellIndex];
}
// 输出处理后的所有单元格值
cout << result.str() << endl;
return 0; // 程序正常结束
}
99.篮球游戏【队列】
#include<bits/stdc++.h>
using namespace std;
vector<int> in;
vector<int> out;
deque<int> dq;
string res = "";
int main(){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
while(getline(is,buffer,',')){
int tmp = stoi(buffer);
in.push_back(tmp);
}
string tmp;
getline(cin,tmp);
istringstream ss(tmp);
while(getline(ss,buffer,',')){
int tmp = stoi(buffer);
out.push_back(tmp);
}
int i,j;
int n = in.size();
for(i=0,j=0;i<n&&j<n;i++){
if(in[i] == out[j]){
if(dq.empty()){
res+="L";
j++;
}else{
res+="R";
j++;
}
while(!dq.empty()){
if(dq.front() == out[j]){
res+="L";
j++;
dq.pop_front();
}else if(dq.back() == out[j]){
res+="R";
j++;
dq.pop_back();
}else break;
}
}else{
dq.push_back(in[i]);
}
}
while(!dq.empty()){
if(dq.front() == out[j]){
res+="L";
j++;
dq.pop_front();
}else if(dq.back() == out[j]){
res+="R";
j++;
dq.pop_back();
}else break;
}
if(!dq.empty()){
cout<<"NO";
return 0;
}
cout<<res<<endl;
}
102.内存冷热标记【哈希】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
map<int,int> pages;
for(int i=0;i<n;i++){
int x;
cin>>x;
pages[x]++;
}
int t;
cin>>t;
vector<pair<int,int>> res;
int cnt = 0;
for(auto x:pages){
if(x.second>=t){
cnt++;
res.push_back(make_pair(x.first,x.second));
}
}
sort(res.begin(),res.end(),[](pair<int,int> p1, pair<int,int> p2){
if(p1.second == p2.second){
return p1.first<p2.first;
}else return p1.second>p2.second;
});
if(cnt == 0){
cout<<0;
return 0;
}else{
cout<<cnt<<endl;
for(auto x:res) cout<<x.first<<endl;
}
return 0;
}
103.求最多可以派出多少支团队【贪心】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> ability(n);
for(int i=0;i<n;i++) cin>>ability[i];
int low_ability;
cin>>low_ability;
sort(ability.begin(),ability.end());
int res = 0;
int i = 0, j =n-1;
if(ability[i]>=low_ability){
res = n;
cout<<res;
return 0;
}
while(i<j){
if(ability[j]>=low_ability){
res++;
j--;
}else if(ability[i] + ability[j] >=low_ability){
res++;
i++;
j--;
}else{
i++;
}
}
cout<<res<<endl;
}
104.孙悟空吃蟠桃: 二分查找
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <climits>
using namespace std;
int calHourUsed(vector<int>& nums, int k) {
int hour = 0;
for (int p : nums) {
hour += ceil((double) p / k);
}
return hour;
}
int getMax(vector<int>& nums) {
int max = INT_MIN;
for (int num : nums) {
max = std::max(max, num);
}
return max;
}
int main() {
string input;
getline(cin, input);
string input2;
getline(cin, input2);
vector<int> nums;
size_t pos = 0;
while ((pos = input.find(' ')) != string::npos) {
nums.push_back(stoi(input.substr(0, pos)));
input.erase(0, pos + 1);
}
nums.push_back(stoi(input));
int h = stoi(input2);
int left = 1;
int right = getMax(nums) + 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (calHourUsed(nums, mid) <= h) {
right = mid;
} else {
left = mid + 1;
}
}
if (nums.size() > h) {
cout << 0 << endl;
} else {
cout << left << endl;
}
return 0;
}
105.贪吃的猴子
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
// 计算猴子能获取的最大香蕉数
int maxBananas(const vector<int>& numbers, int N) {
int total = 0; // 初始化数组总和为0
// 计算数组中所有香蕉的总数
for (int number : numbers) {
total += number;
}
// 如果N等于数组长度,猴子可以拿走所有的香蕉
if (N == numbers.size()) {
return total;
}
int minWindowSum = INT_MAX; // 初始化最小窗口和为最大整数值
int currentWindowSum = 0; // 初始化当前窗口和为0
int windowSize = numbers.size() - N; // 计算窗口大小
// 初始化窗口的和
for (int i = 0; i < windowSize; i++) {
currentWindowSum += numbers[i];
}
minWindowSum = currentWindowSum; // 将当前窗口和赋值给最小窗口和
// 通过滑动窗口计算最小窗口和
for (int i = windowSize; i < numbers.size(); i++) {
// 窗口滑动,加上新进入窗口的元素,减去离开窗口的元素
currentWindowSum += numbers[i] - numbers[i - windowSize];
// 更新最小窗口和
minWindowSum = min(minWindowSum, currentWindowSum);
}
// 猴子能获取的最大香蕉数是总和减去最小窗口和
return total - minWindowSum;
}
int main() {
int len; // 读取数组长度
cin >> len;
vector<int> numbers(len); // 创建数组存储每串香蕉的数量
for (int i = 0; i < len; i++) {
cin >> numbers[i]; // 循环读取每串香蕉的数量
}
int N; // 读取猴子可以获取的次数
cin >> N;
cout << maxBananas(numbers, N) << endl; // 输出猴子能获取的最大香蕉数
return 0;
}
107.寻找最富裕的小家庭【DFS】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
map<int,int> mp;
vector<int> peo(n+1);
for(int i=1;i<=n;i++){
cin>>peo[i];
mp[i] = peo[i];
}
for(int i=0;i<n-1;i++){
int x,y;
cin>>x>>y;
mp[x]+=peo[y];
}
int maxn = -1;
for(auto x:mp){
maxn = max(maxn,x.second);
}
cout<<maxn<<endl;
return 0;
}
108.抢7游戏
#include<bits/stdc++.h>
using namespace std;
int main(){
int m;
cin>>m;
//dp[i][0]:A 选择 i 的方案数
//dp[i][1]:B 选择 i 的方案数
vector<vector<long long>> dp(m+2,vector<long long>(2,0));
dp[m][0] = 1;
dp[m][1] = 0;
for(int i=m-1;i>=7;i--){
dp[i][0] = dp[i+1][1] + dp[i+2][1];
dp[i][1] = dp[i+1][0] + dp[i+2][0];
}
cout<<dp[7][1];
}
109.分月饼: 动态规划
#include<bits/stdc++.h>
using namespace std;
//输出有多少种月饼分法
int main(){
//m个员工,n个月饼
int m,n;
cin>>m>>n;
//dp[i][j][k]:第 i 个人分到 j 个月饼时,前 i个数人一共分到 k 个月饼的方案数
vector<vector<vector<int> > > dp(m+1,vector<vector<int>>(n-m+2,vector<int>(n+1,0)));
// 初始化:因为要满足得到的序列递增,所以第一个人分得的月饼数不能超过平均值
for (int j = 1; j <= n / m; j++) {
dp[1][j][j] = 1;
}
//i的最大取值为 m-1 ,因为内层循环会取到 m
for(int i=1;i<m;i++){
for(int j=1;j<=n-m+1;j++){
for(int k=i;k<=n;k++){
for (int d=0;d<=3;d++) {
if(j+d<=n-m+1 && k+j+d<=n){
dp[i+1][j+d][k+j+d]+=dp[i][j][k];
}
}
}
}
}
int res = 0;
for(int j=1;j<=n-m+1;j++){
res+=dp[m][j][n];
}
cout<<res<<endl;
return 0;
}
110.求幸存数之和: 数组
#include <iostream>
#include <list>
#include <numeric>
#include <sstream>
#include <string>
#include <vector>
#include <numeric>
using namespace std;
// 计算幸存数之和
int sumOfLeft(int nums[], int jump, int left, int length) {
// 如果幸存数量大于等于数组长度,则直接返回数组元素之和
if (left >= length) {
return accumulate(nums, nums + length, 0);
}
// 使用vector存储数组元素,方便删除操作
vector<int> lst(nums, nums + length);
// 初始化起跳点索引为0
int index = 0;
// 当列表大小大于幸存数量时,执行删除操作
while (lst.size() > left) {
// 计算下一个要删除元素的索引
index = (index + jump + 1) % lst.size();
// 删除计算出的索引处的元素
lst.erase(lst.begin() + index);
// 由于删除元素后,列表会缩短,下一个起跳点应当向前移动一位
index = index - 1 ;
}
// 计算并返回剩余元素之和
return accumulate(lst.begin(), lst.end(), 0);
}
int main() {
string line;
vector<int> nums;
int jump, left;
// 读取一行输入,按逗号分割,转换为整数数组
getline(cin, line);
stringstream ss(line);
string num;
while (getline(ss, num, ',')) {
nums.push_back(stoi(num));
}
// 读取跳数
cin >> jump;
// 读取幸存数量
cin >> left;
// 输出幸存数之和
cout << sumOfLeft(&nums[0], jump, left, nums.size()) << endl;
return 0;
}
113.二叉树的广度优先遍历: 树
#include <iostream>
#include <unordered_map>
#include <queue>
using namespace std;
struct TreeNode {
char val;
TreeNode *left;
TreeNode *right;
TreeNode(char val) : val(val), left(nullptr), right(nullptr) {}
};
TreeNode *buildTree(unordered_map<char, int> &dic, string &postorder, string &inorder, int postEnd, int inStart, int inEnd) {
if (inStart > inEnd) {
return nullptr;
}
char nodeVal = postorder[postEnd];
int idxNode = dic[nodeVal];
TreeNode *node = new TreeNode(nodeVal);
node->left = buildTree(dic, postorder, inorder, postEnd - (inEnd - idxNode) - 1, inStart, idxNode - 1);
node->right = buildTree(dic, postorder, inorder, postEnd - 1, idxNode + 1, inEnd);
return node;
}
string levelOrderTraverse(TreeNode *root) {
string ans;
queue<TreeNode *> q;
q.push(root);
while (!q.empty()) {
TreeNode *node = q.front();
q.pop();
ans.push_back(node->val);
if (node->left) {
q.push(node->left);
}
if (node->right) {
q.push(node->right);
}
}
return ans;
}
int main() {
string postorder, inorder;
cin >> postorder >> inorder;
unordered_map<char, int> dic;
for (int i = 0; i < inorder.size(); ++i) {
dic[inorder[i]] = i;
}
TreeNode *root = buildTree(dic, postorder, inorder, inorder.size() - 1, 0, inorder.size() - 1);
string ans = levelOrderTraverse(root);
cout << ans << endl;
return 0;
}
115.反射计数
#include <iostream>
#include <vector>
using namespace std;
// 计算物体在移动过程中经过的1的数量的函数
int countOnes(int w, int h, int x, int y, int sx, int sy, int t, vector<vector<int>>& matrix) {
int count = matrix[y][x];
while (t-- > 0) {
x += sx;
y += sy;
// 如果物体撞到左右边界,反转x轴方向速度分量
if (x == 0 || x == w - 1) sx = -sx;
// 如果物体撞到上下边界,反转y轴方向速度分量
if (y == 0 || y == h - 1) sy = -sy;
// 每次移动后,如果新位置是1,则累加到计数器
count += matrix[y][x];
}
return count;
}
int main() {
int w, h, x, y, sx, sy, t;
cin >> w >> h >> x >> y >> sx >> sy >> t;
vector<vector<int>> matrix(h, vector<int>(w));
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
char ch;
cin >> ch;
matrix[i][j] = ch - '0';
}
}
cout << countOnes(w, h, x, y, sx, sy, t, matrix) << endl;
return 0;
}
117.围棋的气【哈希】
#include<bits/stdc++.h>
using namespace std;
int chess[20][20];
bool vis[20][20];
int main(){
int bs = 0,ws = 0;
string s1,s2;
getline(cin,s1);
getline(cin,s2);
vector<pair<int,int> > v1;
vector<pair<int,int> > v2;
int x,y;
istringstream black(s1);
istringstream white(s2);
//将有棋子的坐标标记
while(black>>x>>y){
v1.push_back(make_pair(x,y));
vis[x][y] = true;
}
//将字符串每次赋予给两个变量
while(white>>x>>y){
v2.push_back(make_pair(x,y));
vis[x][y] = true;
}
for(int i=0;i<v1.size();i++){
int x = v1[i].first;
int y = v1[i].second;
if(x+1<19&&!vis[x+1][y]) chess[x+1][y] = 1;
if(x-1>=0&&!vis[x-1][y]) chess[x-1][y] = 1;
if(y+1<19&&!vis[x][y+1]) chess[x][y+1] = 1;
if(y-1>=0&&!vis[x][y-1]) chess[x][y-1] = 1;
}
for(int i=0;i<19;i++){
for(int j=0;j<19;j++){
if(chess[i][j] == 1) bs++;
}
}
memset(chess,0,sizeof(chess));
for(int i=0;i<v2.size();i++){
int x = v2[i].first;
int y = v2[i].second;
if(x+1<19&&!vis[x+1][y]) chess[x+1][y] = 1;
if(x-1>=0&&!vis[x-1][y]) chess[x-1][y] = 1;
if(y+1<19&&!vis[x][y+1]) chess[x][y+1] = 1;
if(y-1>=0&&!vis[x][y-1]) chess[x][y-1] = 1;
}
for(int i=0;i<19;i++){
for(int j=0;j<19;j++){
if(chess[i][j] == 1) ws++;
}
}
cout<<bs<<' '<<ws<<endl;
}
字符串表达式求值
#include<bits/stdc++.h>
using namespace std;
//定义操作符栈和操作数栈
stack<int> num;
stack<char> op;
//eval函数的功能是弹出栈顶两个操作数a和b,弹出栈顶的操作符c,根据操作符,将a与b做运算得到结果x再压回栈中
void eval(){
int b = num.empty()? 0 : num.top();
num.pop();
int a = num.empty()? 0 :num.top();
num.pop();
char c = op.top();
op.pop();
int x;
if(c == '+') x = a + b;
else if(c == '-') x = a - b;
else if(c == '*') x = a * b;
else x = a / b;
num.push(x);
}
int main(){
//读入表达式字符串
string s;
cin >> s;
//定义四个操作符的优先级: 加减的优先级比乘除低,这里定义加减是1,乘除是2
map<char, int> mp = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
//从左到右扫描一遍字符串
for(int i = 0; i < s.size(); i++){
if(isdigit(s[i])){
//operand存储操作数,因为操作数在字符串里面可能有连续几位
int j = i, operand = 0;
//将字符串"1234"转换成数字1234的代码
while(j < s.size() && isdigit(s[j])){
operand = operand * 10 + s[j] - '0';
j++;
}
num.push(operand); //将操作数压入栈中
i = j - 1; //for循环里面会执行i++,所以这里j需要减去1
}else if(s[i] == '('){
op.push(s[i]); //左括号则压栈
}else if(s[i] == ')'){
//右括号则一直匹配,直到碰到左括号位置
while(op.top() != '(') eval();
op.pop();
}else{
//若栈不为空且没有碰到左括号且栈顶元素的优先级大于等于该操作符的优先级
while(op.size() && op.top() != '(' && mp[op.top()] >= mp[s[i]]) eval();
op.push(s[i]); //将操作符压入栈中
}
}
//操作到运算符栈空为止
while(op.size()) eval();
//最后运算符栈顶保存的元素即为最后表达式的值
cout << num.top() << endl;
return 0;
}
2023Q2B-选修课
#include<bits/stdc++.h>
using namespace std;
//将学生的学号和成绩一一对应
map<string, int> buildDict(const vector<string>& lst) {
map<string, int> dic;
for (const string& item : lst) {
stringstream ss(item);
string num, gradeStr;
//getline的这个用法
getline(ss, num, ',');
getline(ss, gradeStr, ',');
int grade = stoi(gradeStr);
dic[num] = grade;
}
return dic;
}
int main() {
string course1, course2;
getline(cin, course1);
getline(cin, course2);
stringstream ss1(course1), ss2(course2);
vector<string> lst1, lst2;
string token;
while (getline(ss1, token, ';')) {
lst1.push_back(token);
}
while (getline(ss2, token, ';')) {
lst2.push_back(token);
}
//为两门课程分别建立学号和成绩的对应
map<string, int> dic1 = buildDict(lst1);
map<string, int> dic2 = buildDict(lst2);
//建立 班级号+有两门选修课的学生学号 的映射
map<string, vector<string>> result;
//找到 有两门选修课的学生学号
for (const auto& stu : dic2) {
if (dic1.find(stu.first) != dic1.end()) {
string classNum = stu.first.substr(0, 5);
result[classNum].push_back(stu.first);
}
}
if (result.empty()) {
cout << "NULL" << endl;
} else {
for (auto res : result) {
//输出班级号
cout << res.first << endl;
//保存某班级的学生的学号列表
vector<string> stuList = result[res.first];
//按照两门选修课成绩和的降序,成绩和相同时按照学号升序
//[&]:表示捕获外部作用域中的所有变量,并且以引用的方式传递给 lambda 表达式。这里的目的是让 lambda 表达式内部能够访问 dic1 和 dic2 这两个外部作用域中的 unordered_map 对象
//&:表示引用传递,即 lambda 表达式内部可以访问到外部作用域中的变量。
sort(stuList.begin(), stuList.end(), [&](const string& a, const string& b) {
int sumA = dic1[a] + dic2[a];
int sumB = dic1[b] + dic2[b];
if (sumA != sumB) {
return sumA > sumB;
}
return a < b;
});
for (size_t i = 0; i < stuList.size(); ++i) { //size_t:C中任何对象所能达到的最大长度,它是无符号整数。
cout << stuList[i];
if (i != stuList.size() - 1) {
cout << ";";
}
}
cout << endl;
}
}
return 0;
}
2023Q1A-相同数字的积木游戏
#include<bits/stdc++.h>
using namespace std;
//数字相同且所处位置最远的 2 块积木块,计算他们的距离
int main(){
int n;
cin>>n;
map<int,set<int>> mp;
int dis = -1;
for(int i=0;i<n;i++){
int x;
cin>>x;
mp[x].insert(i);
}
for(auto jm:mp){
if(jm.second.size()>1){
dis = max(dis,(*jm.second.rbegin()-*jm.second.begin()));
}
}
cout<<dis<<endl;
return 0;
}
2023Q1A-寻找密码
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
map<string,int> mp;
set<string> st;
vector<string> res;
while(getline(is,buffer,' ')){
mp[buffer] = 1;
st.insert(buffer);
}
for(auto buf:st){
int flag = 0;
if(buf.size()<=1) continue;
for(int i=0;i<buf.size()-1;i++){
string tmp = buf.substr(0,i+1);
if(mp.count(tmp) == 0){
flag = 1;
break;
}
}
if(flag == 0) res.push_back(buf);
}
sort(res.begin(),res.end(),[](string s1, string s2){
if(s1.size() == s2.size()){
return s1>s2;
}else{
return s1.size()>s2.size();
}
});
if(res.empty()){
cout<<""<<endl;
return 0;
}else{
cout<<*res.begin()<<endl;
return 0;
}
}
2023C-找最小数【单调栈】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int n;
cin>>n;
stack<char> st;
//字符串升序时最小
for(int i=0;i<s.size();i++) {
while(!st.empty()&&st.top()>s[i]&&n){//只弹出栈顶比当前元素大的,注意没有等号
st.pop();
n--;
}
st.push(s[i]);
}
//注意坑点!
while(n){
st.pop();
n--;
}
string res = "";
while(!st.empty()){
res = st.top() + res;
st.pop();
}
cout<<res<<endl;
return 0;
}
2023Q1A-两数之和绝对值最小
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
vector<int> vi;
while(getline(is,buffer,' ')){
vi.push_back(stoi(buffer));
}
sort(vi.begin(),vi.end());
int i = 0, j = vi.size()-1;
int x = 0,y = 0;
int minAbs = abs(vi[i]+vi[j]);
while(i<j){
if(abs(vi[i]+vi[j])<minAbs){
minAbs = abs(vi[i]+vi[j]);
x = vi[i];
y = vi[j];
}
if(abs(vi[i+1]+vi[j])<abs(vi[i]+vi[j-1])){
i++;
}else if(abs(vi[i+1]+vi[j])>=abs(vi[i]+vi[j-1])){
j--;
}
}
cout<<x<<' '<<y<<' '<<minAbs<<endl;
}
2023Q1A-双十一
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int r;
cin>>r;
string buffer;
istringstream is(s);
vector<int> m;
while(getline(is,buffer,',')){
m.push_back(stoi(buffer));
}
sort(m.begin(),m.end());
int res = 0;
for(int i=0;i<m.size()-1;i++){
int j = i+1,k = m.size()-1;
while(j<k){
int x = m[i] + m[j] + m[k];
if(x == r){
cout<<x<<endl;
return 0;
}
if(x<r){
j++;
res = max(res,x);
}else if(x>r){
k--;
}
}
}
if(res == 0) cout<<-1<<endl;
else{
cout<<res<<endl;
}
return 0;
}
2023Q1A-快递货车
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> kd;
string s;
getline(cin,s);
int weight;
cin>>weight;
string buffer;
istringstream is(s);
while(getline(is,buffer,',')){
kd.push_back(stoi(buffer));
}
sort(kd.begin(),kd.end());
int res = 0;
for(int i=0;i<kd.size();i++){
if(kd[i]<=weight){
res++;
weight-=kd[i];
}else break;
}
cout<<res<<endl;
return 0;
}
2023C-停车找车位【贪心】
题解
- 分两种情况:
- 左边没有车或者右边没有车,即停在边上的位置
- 左边和右边均有车,即停在两车之间
C++
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
string str = "";
while(getline(is,buffer,',')){
str+=buffer;
}
int left, right;
int n = str.size();
//找到最左边第一个车的停车的位置
for(int i=0;i<n;i++){
if(str[i] == '1'){
left = i;
break;
}
}
找到最右边第一个车的停车的位置
for(int i=n-1;i>=0;i--){
if(str[i] == '1'){
right = i;
break;
}
}
//如果存在一边没有停车的情况,则存下这种情况下的最远距离
int maxdis = max(left,n-1-right);
int dis = 0;
int maxn = 0;
//找到两边都停车的情况下,未停车的区间最大长度
for(int i=left;i<=right;i++){
if(str[i] == '1'){
dis = 0;
}else if(str[i] == '0'){
dis++;
maxn = max(maxn,dis);
}
}
if((maxn+1)/2<maxdis){
cout<<maxdis<<endl;
return 0;
}else{
cout<<(maxn+1)/2<<endl;
return 0;
}
}
2023Q1A-贪心的商人【DP/贪心】
解题思路
注意,本题的核心逻辑和LC122. 买卖股票的最佳时机II完全一致。
注意到各种商品之间是相互独立的,即第i
件商品的买卖与第j
件商品的买卖无关。因此对于每一种商品我们都可以单独计算其利润,再将利润加总即可。
又注意到对于某特定商品而言,存在关系总利润 = 数量 × 单件利润
。故我们仅需计算某商品单件能取得的最大利润,再直接乘以每件商品的最大库存数number[i]
即为该种商品能取得的总利润。
计算单件商品最大利润的核心代码完全无需修改
C++
#include<bits/stdc++.h>
using namespace std;
int main(){
int number;
int days;
cin>>number; // 输入商品的数量 number
cin>>days; // 输入商人售货天数 days
vector<int> item(number);
for(int i=0;i<number;i++) cin>>item[i]; //输入仓库限制每件商品的最大持有数量是 item[index]
vector<vector<int> > item_price(number,vector<int>(days));//二维vector的定义方式
for(int i=0;i<number;i++){
for(int j=0;j<days;j++)
cin>>item_price[i][j];
}
int res = 0;
for(int i=0;i<number;i++){
int profit = 0;
//记录每件商品单件可以获得的最大的利润
for(int j=1;j<days;j++){
if(item_price[i][j]>item_price[i][j-1]) profit+=(item_price[i][j]-item_price[i][j-1]);
}
//计算该商品的总利润=商品个数*单件可以获得的最大的利润
res+=(profit*item[i]);
}
cout<<res<<endl;
return 0;
}
2023C-身高体重排序【模拟】
#include<bits/stdc++.h>
using namespace std;
//身高由低到高排列
//对身高相同的人,按体重由轻到重排列
//对于身高体重都相同的人,维持原有的编号顺序关系。
struct Stu{
int hight;
int weight;
int num; //将序号记录下来
};
int main(){
int n;
cin>>n;
//结构体vector的写法,便于结构体排序
vector<Stu> stu(n); //vector分配了空间才能用下标访问
for(int i=0;i<n;i++){
cin>>stu[i].hight;
stu[i].num = i+1; //学生编号是从1开始
}
for(int i=0;i<n;i++) cin>>stu[i].weight;
//注意此lambda函数的写法
sort(stu.begin(),stu.end(),[](Stu st1, Stu st2){
if(st1.hight == st2.hight && st1.weight == st2.weight){
return st1.num<st2.num;
}else if(st1.hight == st2.hight){
return st1.weight < st2.weight;
}else return st1.hight < st2.hight;
});
for(int i=0;i<n;i++) cout<<stu[i].num;
}
2023B-拔河比赛【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<pair<int,int>> peo; //包含两个属性的vector写法
int h,w;
while(cin>>h>>w){
peo.push_back(make_pair(h,w));
}
sort(peo.begin(),peo.end(),[](pair<int,int> p1, pair<int,int> p2){
if(p1.first == p2.first){
return p1.second>=p2.second;
}else{
return p1.first>p2.first;
}
});
for(int i=0;i<10;i++) cout<<peo[i].first<<' '<<peo[i].second<<endl;
}
2023C-身高排序【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
//和小明身高差绝对值最小的小朋友排在前面
//如果两个小朋友和小明身高差一样,则个子较小的小朋友排在前面
int main(){
int h,n;
cin>>h>>n;
vector<int> hight(n);
for(int i=0;i<n;i++) cin>>hight[i];
//[&]:表示捕获外部作用域中的所有变量,并且以引用的方式传递给 lambda 表达式。
sort(hight.begin(),hight.end(),[&](int h1, int h2){
int x = abs(h1-h);
int y = abs(h2-h);
if(x == y){
return h1<h2;
}else{
return x<y;
}
});
for(auto x:hight) cout<<x<<' ';
}
2023B-磁盘容量【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
long long stoint(string s){
long long res = 0;
long long oper = 0;
for(int i=0;i<s.size();i++){
if(isdigit(s[i])){
oper = oper*10+s[i]-'0';
}else{
if(s[i] == 'M'){
res+=oper;
oper = 0;
}else if(s[i] == 'G'){
res+=(oper*1024);
}else if(s[i] == 'T'){
res+=(oper*1024*1024);
oper = 0;
}
}
}
return res;
}
int main(){
int n;
cin>>n;
vector<pair<string,long long> > vi(n);
for(int i=0;i<n;i++){
cin>>vi[i].first;
for(int j=0;j<vi[i].first.size();j++){
vi[i].second = stoint(vi[i].first);
}
}
sort(vi.begin(),vi.end(),[](pair<string,long long> v1,pair<string,long long> v2){
return v1.second<v2.second;
});
for(int i=0;i<n;i++) cout<<vi[i].first<<endl;
}
2023B-日志时间排序【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
struct tim{
int h;
int m;
float s;
string t;
};
int main(){
int n;
cin>>n;
vector<tim> time(n);
for(int i=0;i<n;i++){
string s;
cin>>s;
time[i].t = s;
string h,m,ss;
istringstream is(s);
// 注意这种getline分隔字符串的方法
getline(is,h,':');
getline(is,m,':');
getline(is,ss,':');
time[i].h = stoi(h);
time[i].m = stoi(m);
time[i].s = stof(ss);
}
sort(time.begin(),time.end(),[](tim t1, tim t2){
if(t1.h == t2.h && t1.m == t2.m){
return t1.s<=t2.s;
}else if(t1.h == t2.h){
return t1.m<t2.m;
}else return t1.h<t2.h;
});
for(int i=0;i<n;i++) cout<<time[i].t<<endl;
}
2023C-最低位排序【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
//按照数组最低位从小到大进行排序
//最低位相同的元素,相对位置保持不变 ==>stable_sort()
//当数组元素为负值时,最低位等同于去除符号位后对应值最低位。
int main(){
string s;
getline(cin,s);
string buffer;
istringstream is(s);
vector<pair<string,char>> vi;
while(getline(is,buffer,',')){
int len = buffer.size();
char c = buffer[len-1];
vi.push_back(make_pair(buffer,c));
}
//注意此地要用stable_sort()!!!
stable_sort(vi.begin(),vi.end(),[](pair<string,char> v1,pair<string,char> v2){
return v1.second<v2.second;
});
for(int i=0;i<vi.size();i++){
cout<<vi[i].first;
if(i!=vi.size()-1) cout<<',';
}
}
2023C-智能成绩表【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<string> subjects(m);
for(int i=0;i<m;i++) cin>>subjects[i];
map<string,vector<int>> stu;
vector<string> name;
for(int i=0;i<n;i++){
string s;
cin>>s;
name.push_back(s);
for(int j=0;j<m;j++){
int x;
cin>>x;
stu[s].push_back(x);
}
}
string pivot;
cin>>pivot;
//要比较的科目是第几个科目
int pos=-1;
for(int i=0;i<m;i++){
if(subjects[i] == pivot){
pos = i;
break;
}
}
stable_sort(name.begin(),name.end(),[&](string s1,string s2){
if(pos == -1){//如果该科目不存在
int res1 = 0,res2 = 0;
for(int i=0;i<m;i++) res1+=stu[s1][i];
for(int i=0;i<m;i++) res2+=stu[s2][i];
if(res1 == res2){
return s1<s2;
}else return res1>res2;
}else if(stu[s1][pos] == stu[s2][pos]){//该科目的分数相同
return s1<s2;
}else return stu[s1][pos] > stu[s2][pos];
});
for(auto x:name) cout<<x<<' ';
}
2023B-VLAN资源池【模拟、排序】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int id;
cin>>id;
string buffer;
istringstream is(s);
vector<pair<int,int>> vi;
while(getline(is,buffer,',')){
string start;
string finsh;
if(buffer.find('-') == -1){
start = finsh = buffer;
int s = stoi(start);
int f = stoi(start);
if(s!=id) vi.push_back(make_pair(s,f));
}
else {
istringstream ss(buffer);
getline(ss,start,'-');
getline(ss,finsh,'-');
int s = stoi(start);
int f = stoi(finsh);
if(s == id) vi.push_back(make_pair(s+1,f));
else if(f == id) vi.push_back(make_pair(s,f-1));
else if(id>s&&id<f){
vi.push_back(make_pair(s,id-1));
vi.push_back(make_pair(id+1,f));
}else{
vi.push_back(make_pair(s,f));
}
}
}
sort(vi.begin(),vi.end(),[](pair<int,int> p1,pair<int,int> p2){
return p1.first<p2.first;
});
for(int i=0;i<vi.size();i++){
if(vi[i].first == vi[i].second) cout<<vi[i].first;
else cout<<vi[i].first<<'-'<<vi[i].second;
if(i<vi.size()-1) cout<<',';
}
}
2023B-查字典
2023C-字符串分割(二)
#include<bits/stdc++.h>
using namespace std;
int main(){
int k;
cin>>k;
getchar();
string s;
getline(cin,s);
vector<string> res;
string buffer;
istringstream is(s);
getline(is,buffer,'-');
res.push_back(buffer);
string str = "";
while(getline(is,buffer,'-')){
str+=buffer;
}
int i = 0;
int len = str.size();
while(i<len){
string s = str.substr(i,k);
int l = 0,u = 0;
for(int i=0;i<s.size();i++){
if(islower(s[i])) l++;
if(isupper(s[i])) u++;
}
if(l>u){
for(int i=0;i<s.size();i++) s[i] = tolower(s[i]);
}else if(l<u){
for(int i=0;i<s.size();i++) s[i] = toupper(s[i]);
}
res.push_back(s);
i+=k;
}
for(int i=0;i<res.size();i++){
cout<<res[i];
if(i<res.size()-1){
cout<<'-';
}
}
}
2023C-GPU调度
#include<bits/stdc++.h>
using namespace std;
int main(){
//一秒最多执行 n 个任务
int n;
cin>>n;
int m;
cin>>m;
vector<int> projects(m);
for(int i=0;i<m;i++){
cin>>projects[i];
}
int sum = 0;
int time = 0;
for(int i=0;i<m;i++){
sum+=projects[i];
if(sum<=n){
time++;
sum = 0;
}else{
time++;
sum-=n;
}
}
while(sum>0){
sum-=n;
time++;
}
cout<<time;
}
2023C-回收银饰
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
priority_queue<int> q;
for(int i=0;i<n;i++){
int x;
cin>>x;
q.push(x);
}
while(q.size()>=3){
int x = q.top();
q.pop();
int y = q.top();
q.pop();
int z = q.top();
q.pop();
if(x == y == z) continue;
else if(x == y && y!=z){
int tmp = abs(z-y);
q.push(tmp);
}else if(x!=y && y == z){
int tmp = abs(y-x);
q.push(tmp);
}else if(x!=y && y!=z){
int tmp = abs((z-y)-(y-x));
if(tmp!=0) q.push(tmp);
}
}
if(q.size()!=0) cout<<q.top();
else cout<<0;
}
2023C-小明能到达的最大坐标值
#include<bits/stdc++.h>
using namespace std;
int main(){
//含有异常的情况处理
try{
int res = 0;
int maxdis = 0;
int n;
cin>>n;
int m;
cin>>m;
vector<int> steps(n);
for(int i=0;i<n;i++){
cin>>steps[i];
}
for(int i=0;i<n;i++){
res+=steps[i];
if(steps[i] == m){
if(steps[i]>0) res++;
if(steps[i]<0) res--;
}
maxdis = max(maxdis,res);
}
cout<<maxdis;
}catch(...){
cout<<12345<<endl;
}
}
2023C-比赛的冠亚季军【模拟、数组】
题目描述模糊
//我的答案
#include<bits/stdc++.h>
using namespace std;
int main(){
queue<pair<int,int>> q;
string s;
getline(cin,s);
string buffer;
istringstream is(s);
int i = 0;
while(getline(is,buffer,' ')){
q.push(make_pair(i,stoi(buffer)));
i++;
}
while(q.size()>3){
pair<int,int> p1 = q.front();
q.pop();
pair<int,int> p2 = q.front();
q.pop();
if(p1.second == p2.second){
if(p1.first < p2.first){
q.push(p1);
}else if(p1.first > p2.first){
q.push(p2);
}
}else if(p1.second>p2.second) q.push(p1);
else if(p1.second<p2.second) q.push(p2);
}
vector<int> res;
while(!q.empty()){
if(q.size() == 1){
res.push_back(q.front().first);
break;
}
pair<int,int> p;
pair<int,int> pp;
pair<int,int> p1 = q.front();
q.pop();
pair<int,int> p2 = q.front();
q.pop();
if(p1.second == p2.second){
if(p1.first<p2.first){
p = p1;
pp = p2;
}else{
p = p2;
pp = p1;
}
}else if(p1.second>p2.second){
p = p1;
pp = p2;
}else{
p = p2;
pp = p1;
}
res.push_back(pp.first);
q.push(p);
}
reverse(res.begin(),res.end());
for(auto x:res) cout<<x<<' ';
}
//标答
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<pair<int, int>> nums;
string input;
getline(cin, input);
istringstream iss(input);
int num, idx = 0;
while (iss >> num) {
nums.push_back(make_pair(num, idx));
idx++;
}
while (nums.size() >= 5) {
vector<pair<int, int>> newNums;
for (size_t i = 0; i < nums.size() - 1; i += 2) {
if (nums[i].first >= nums[i + 1].first) {
newNums.push_back(nums[i]);
} else {
newNums.push_back(nums[i + 1]);
}
}
if (nums.size() % 2 == 1) {
newNums.push_back(nums[nums.size() - 1]);
}
nums = newNums;
}
if (nums.size() == 3) {
if (nums[1].first > nums[0].first){
swap(nums[0], nums[1]);
}
for (size_t i = 0; i < 3; i++) {
cout << nums[i].second << " ";
}
cout << endl;
} else if (nums.size() == 4) {
pair<int, int> A, B, C, D;
A = nums[0];
B = nums[1];
C = nums[2];
D = nums[3];
if (A.first >= B.first) {
nums[0] = A;
nums[2] = B;
} else {
nums[0] = B;
nums[2] = A;
}
if (C.first >= D.first) {
nums[1] = C;
nums[3] = D;
} else {
nums[1] = D;
nums[3] = C;
}
if (nums[1].first > nums[0].first) {
swap(nums[0], nums[1]);
}
if (nums[3].first > nums[2].first) {
swap(nums[2], nums[3]);
}
for (size_t i = 0; i < 3; i++) {
cout << nums[i].second << " ";
}
cout << endl;
}
return 0;
}
2023C-灰度图恢复
#include<bits/stdc++.h>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
getchar();
string s;
getline(cin,s);
queue<int> q;
vector<int> vi;
string buffer;
istringstream is(s);
while(getline(is,buffer,' ')){
q.push(stoi(buffer));
}
while(!q.empty()){
int weight = q.front();
q.pop();
int cnt = q.front();
q.pop();
while(cnt--) vi.push_back(weight);
}
int row,col;
cin>>row>>col;
cout<<vi[row*n+col];
}
2023C-高效货运【模拟、数学】
#include<bits/stdc++.h>
using namespace std;
int main(){
int wa,wb,wt,pa,pb;
cin>>wa>>wb>>wt>>pa>>pb;
int maxProfit = 0;
int x = wt/wa;
for(int i=x;i>=1;i--){
if((wt-i*wa)%wb == 0){
int y = (wt-i*wa)/wb;
int profit = i*pa+y*pb;
maxProfit = max(maxProfit,profit);
}
}
cout<<maxProfit;
}
2023C-整数分解
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
int maxR = (t+1)/2;
int l = 1;
int result = 1;
vector<string> res;
res.push_back(to_string(t));
int sum = 0;
for(int r = 1;r<=maxR;r++){
sum+=r;
while(sum>t){
sum-=l;
l++;
}
if(sum == t){
string s = "";
for(int i=l;i<=r;i++){
s+=to_string(i);
if(i<r) s+="+";
}
res.push_back(s);
result++;
}
}
sort(res.begin(),res.end(),[](string s1, string s2){
return s1.size()<s2.size();
});
for(auto s:res) cout<<to_string(t)<<"="<<s<<endl;
cout<<"Result:"<<result<<endl;
}
2023C-找朋友【单调栈】
解题思路
本题是在环型数组中计算每一个元素右侧的下一个更小元素,显然应该使用单调栈来完成。本题和LeetCode503. 下一个更大元素II的方法非常类似。
处理环型数组,可以将数组nums
进行拼接,然后索引遍历的范围在[0, 2*n-1]
进行即可。
PS:由于数据范围最多只有500
,所以O(n^2)
的暴力解是可以接受的。不熟悉单调栈的同学在考试遇到可以尝试使用暴力解。
//暴力解
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> height(n);
for(int i=0;i<n;i++) cin>>height[i];
vector<int> pos(n);
stack<pair<int,int>> st;
for(int i=n-1;i>=0;i--){
while(!st.empty() && st.top().second<=height[i]){
st.pop();
}
pos[i] = st.empty()? 0: st.top().first;
st.push(make_pair(i,height[i]));
}
for(auto x:pos) cout<<x<<' ';
}
2023C-回转寿司
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> food;
int x;
while(cin>>x){
food.push_back(x);
}
int len = food.size();
vector<int> price(len);
for(int i=0;i<len;i++){
int flag = 0;
for(int j=(i+1)%len;j!=i;j = (j+1)%len){
if(food[j]<food[i]){
price[i] = food[i]+food[j];
flag = 1;
break;
}
}
if(!flag) price[i] = food[i];
}
for(auto x:price) cout<<x<<' ';
}
2023C-攀登者2
#include<bits/stdc++.h>
using namespace std;
// 计算从左边空地出发往右,能够攀登并按照原路返回的山峰数量
vector<int> cal_peak_from_left(vector<int>& nums, int route_max, int n) {
vector<int> ans;
vector<int> space_list;
// 记录出发空地的坐标
for (int i = 0; i < n - 1; i++) {
// 如果i为空地,且下一个位置i+1不为空地,则记录位置i,作为一个出发的空地
// (即如果出现连续的空地,只需要储存最右边最靠近山体的空地作为出发的起始位置即可)
if (nums[i] == 0 && nums[i+1] > 0) {
space_list.push_back(i);
}
}
// 考虑每一个起始位置
for (int start : space_list) {
// 设置初始的i为空地start的下一个位置
int i = start + 1;
//记录当前的高度差
int route_num = 0;
// 从start+1出发,向右登山
// 且不能跨过所有山脉爬到另一头的另一个空地
while (i < n && nums[i] != 0) {
// 总高度差新增nums[i]和nums[i-1]之间的高度差
route_num += abs(nums[i] - nums[i - 1]);
// 若总高度差大于等于最大高度差,则无法攀登到最新的i处,退出循环
// 【注意:这里是大于等于,不是大于】
if (route_num >= route_max) {
break;
}
// 若nums[i]是一座山峰,把i存入ans中
// 边界情况
if (i == n - 1 && nums[i] > nums[i - 1]) {
ans.push_back(i);
}
// 非边界情况
else if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) {
ans.push_back(i);
}
// i递增
i++;
}
}
// 返回所有能够到达的山峰的索引
return ans;
}
int main() {
string input;
getline(cin, input);
vector<int> heights;
int power_max; //最大体力
// 解析输入的高度数组
stringstream ss(input);
string buffer;
while (getline(ss, buffer, ',')) {
int num = stoi(buffer);
heights.push_back(num);
}
// 获得数组长度
int n = heights.size();
// 输入最大体力
cin >> power_max;
// 最大体力除以3,表示按照原路返回方式能够攀登的最长高度差
int route_max = power_max / 3;
// 计算从左边空地出发,向右攀爬,并原路返回能到达的山峰
vector<int> ans_from_left = cal_peak_from_left(heights, route_max, n);
// 计算从右边空地出发,向左攀爬,并原路返回能到达的山峰
vector<int> reversed_heights(heights.rbegin(), heights.rend());
vector<int> ans_from_right = cal_peak_from_left(reversed_heights, route_max, n);
// 由于使用了反转,得到的索引也是反转的,需要进一步处理才能得到原heights数组中的索引
for (int i = 0; i < ans_from_right.size(); i++) {
ans_from_right[i] = n - ans_from_right[i] - 1;
}
// 使用 unordered_set 来存储交集的结果,去重
unordered_set<int> ans_set;
for (int val : ans_from_left) {
ans_set.insert(val);
}
for (int val : ans_from_right) {
ans_set.insert(val);
}
// 输出结果
cout << ans_set.size() << endl;
return 0;
}
2023C-解密犯罪时间
#include<bits/stdc++.h>
using namespace std;
// 根据长度为4的数字型字符数组lst,获得下一个时刻的函数
vector<char> getNextTime(vector<char>& lst) {
int HH = stoi(string(1, lst[0]) + string(1, lst[1]));
int MM = stoi(string(1, lst[2]) + string(1, lst[3]));
int new_HH, new_MM;
if (MM < 59) {
new_HH = HH;
new_MM = MM + 1;
} else {
new_MM = 0;
if (HH < 23) {
new_HH = HH + 1;
} else {
new_HH = 0;
}
}
// 构建新数组
vector<char> ans(4);
ans[0] = static_cast<char>('0' + new_HH / 10);
ans[1] = static_cast<char>('0' + new_HH % 10);
ans[2] = static_cast<char>('0' + new_MM / 10);
ans[3] = static_cast<char>('0' + new_MM % 10);
return ans;
}
int main() {
string s;
cin >> s;
vector<char> lst = {s[0], s[1], s[3], s[4]};
unordered_set<char> numsUsedSet(lst.begin(), lst.end());
// 持续循环
while (true) {
// 获得下一个时刻对应的数组lst
lst = getNextTime(lst);
// 若lst中所有字符均在哈希集合中出现过,说明当前lst对应下一个时刻
bool allIn = true;
for (char ch : lst) {
if (numsUsedSet.find(ch) == numsUsedSet.end()) {
allIn = false;
break;
}
}
if (allIn) {
// 输出时刻字符串,并退出循环
cout << lst[0] << lst[1] << ":" << lst[2] << lst[3] << endl;
break;
}
}
return 0;
}
2023C-CPU算力分配
#include<bits/stdc++.h>
using namespace std;
int main(){
int l1,l2;
cin>>l1>>l2;
set<int> st1;
set<int> st2;
int power1 = 0, power2 = 0;
for(int i=0;i<l1;i++){
int x;
cin>>x;
power1+=x;
st1.insert(x);
}
for(int i=0;i<l2;i++){
int x;
cin>>x;
power2+=x;
st2.insert(x);
}
for(set<int>::iterator it = st1.begin();it!=st1.end();it++){
int x = *it;
int y = (2*x-power1+power2)/2;
if(st2.find(y)!=st2.end()){
cout<<x<<' '<<y<<endl;
return 0;
}
}
}
2023C-求满足条件的最长子串的长度【不定滑窗】
#include<bits/stdc++.h>
using namespace std;
int main(){
int res = 0;
string s;
getline(cin,s);
int l = 0;
int cnt = 0;
int tmp = 0;
for(int r = 0;r<s.size();r++){
if(isdigit(s[r])){
tmp++;
res = max(tmp,res);
}else if(isalpha(s[r])){
cnt++;
tmp++;
while(cnt>1){
if(isalpha(s[l])) cnt--;
l++;
tmp--;
}
res = max(res,tmp);
}
}
cout<<res<<endl;
}
2023C-字符串摘要【不定滑窗】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
string str = "";
for(int i=0;i<s.size();i++){
if(isalpha(s[i])) str+=tolower(s[i]);
}
int n = str.size();
map<char,int> mp;
//创建一个从右往左移动的滑窗,可以记录某个字符右边已经存在的个数:mp[c]-1
int r = n-1,l;
vector<pair<char,int> > res;
for(l = n-1;l>=0;l--){
mp[str[l]]++;
char c = str[l];
while(c!=str[r]){
int cnt = r-l;//右指针对应字符的重复个数
//如果是非连续的字符,则输出该字符之后字符串中出现的该字符的次数
if(cnt == 1){
int x = mp[str[r]]-1;
res.push_back(make_pair(str[r],x));
} //如果是连续的字符,则输出该字符的次数
else res.push_back(make_pair(str[r],cnt));
r = l;
}
}
//处理第一个区间的字符
int cnt = r-l;
if(cnt == 1){
int x = mp[str[r]]-1;
res.push_back(make_pair(str[r],x));
}else res.push_back(make_pair(str[r],cnt));
sort(res.begin(),res.end(),[](pair<char,int> p1, pair<char,int> p2){
if(p1.second == p2.second) return p1.first<p2.first;
else return p1.second>p2.second;
});
for(auto x:res) cout<<x.first<<x.second;
}
2023C-最长的指定瑕疵度的元音子串
滑窗三答
**A1:**如果ch
是一个辅音,则窗口中辅音个数win_consonant_num += 1
A2:win_consonant_num > k
,即滑窗子串所对应的瑕疵度超过了瑕疵度阈值k
,left
右移,直到left
指向一个元音。
**A3:**如果ch
是一个元音,且此时瑕疵度恰好为k
,那么可以更新答案。【因为要求首尾的字符都是元音】
#include<bits/stdc++.h>
using namespace std;
int main(){
int flaw;
cin>>flaw;
getchar();
string s;
getline(cin,s);
string yuan = "aeiouAEIOU";
int l=-1,r=-1;
int res = 0;//存储结果
int tmp = 0;//当前区间元素的长度
int cnt = 0;//存储区间内辅音的个数
//找到左边开始第一个元音
for(int i=0;i<s.size();i++){
if(yuan.find(s[i])!=-1){
l = i;
break;
}
}
if(l == s.size()){
cout<<0<<endl;
return 0;
}else{
for(r=l;r<s.size();r++){
if(yuan.find(s[r])!=-1){ //如果右指针是元音
tmp++; //区间元素长度增加
if(cnt == flaw) res = max(tmp,res); //窗口中的辅音个数为k个(即瑕疵度)
}else{ //如果右指针是辅音
cnt++; //辅音个数增加
tmp++; //区间元素长度增加
while(l<s.size() && (cnt>flaw||yuan.find(s[l]) == -1)){
if(yuan.find(s[l]) == -1) cnt--; //如果左指针指向辅音,则向右移动的过程中,辅音个数减少
cnt = cnt<0?0:cnt; //移动过程中左指针可能超过右指针
l++;
tmp--;
tmp = tmp<0?0:tmp; //移动过程中左指针可能超过右指针
}
}
}
}
cout<<res<<endl;
}
2023C-分班【DP】
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
vector<pair<int,char>> stu;
while(getline(cin,s)){
int num;
char op;
char Flag;
istringstream is(s);
is>>num>>op>>Flag;
stu.push_back(make_pair(num,Flag));
}
int n = stu.size();
vector<bool> v(n,0);
vector<int> c1;
vector<int> c2;
for(int i=1;i<n;i++){
if(stu[i].second == 'Y'){
v[i] = v[i-1];
}
else if(stu[i].second == 'N'){
v[i] = !v[i-1];
}
}
for(int i=0;i<n;i++){
if(v[i] == 0){
c1.push_back(stu[i].first);
}else c2.push_back(stu[i].first);
}
sort(c1.begin(),c1.end());
sort(c2.begin(),c2.end());
if(c1.empty()||c2.empty()){
if(c1.empty()){
for(auto x:c2) cout<<x<<' ';
cout<<endl;
}else if(c2.empty()){
for(auto x:c1) cout<<x<<' ';
cout<<endl;
}
return 0;
}
if(c1[0]<c2[0]){
for(auto x:c1) cout<<x<<' ';
cout<<endl;
for(auto x:c2) cout<<x<<' ';
cout<<endl;
} else{
for(auto x:c2) cout<<x<<' ';
cout<<endl;
for(auto x:c1) cout<<x<<' ';
cout<<endl;
}
return 0;
}
2023C-石头剪刀布游戏
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<pair<string,string>> v;
string name,val;
vector<string> win_id;
map<string,int> mp;
while(cin>>name>>val){
v.push_back(make_pair(name,val));
mp[val]++;
}
if(mp.size() == 1||mp.size() == 3){
cout<<"NULL"<<endl;
return 0;
}
if(mp.size() == 2){
map<string,int>::iterator it = mp.begin();
string s1 = it->first;
it++;
string s2 = it->first;
if((s1 == "A"&&s2 == "B")||(s1 == "B"&&s2 == "C")||(s1 == "C"&&s2 == "A")){
for(int i=0;i<v.size();i++){
if(v[i].second == s1){
win_id.push_back(v[i].first);
}
}
sort(win_id.begin(),win_id.end());
for(int i=0;i<win_id.size();i++){
cout<<win_id[i]<<endl;
}
return 0;
}else if((s2 == "A"&&s1 == "B")||(s2 == "B"&&s1 == "C")||(s2 == "C"&&s1 == "A")){
for(int i=0;i<v.size();i++){
if(v[i].second == s2){
win_id.push_back(v[i].first);
}
}
sort(win_id.begin(),win_id.end());
for(int i=0;i<win_id.size();i++){
cout<<win_id[i]<<endl;
}
return 0;
}
}
}
2023C-座位调整
#include<bits/stdc++.h>
using namespace std;
int main(){
string desk;
getline(cin,desk);
if(desk == "0"){
cout<<1;
return 0;
}
string buffer;
istringstream is(desk);
string s = "";
while(getline(is,buffer,',')){
s+=buffer;
}
int n = s.size();
int res = 0;
for(int i=0;i<n;i++){
if(i == 0 && i+1<n && s[i]==s[i+1] &&s[i] =='0'){
res++;
s[i] = '1';
}else if(i == n-1 && i-1>=0 && s[i]==s[i-1] && s[i]=='0'){
res++;
s[i] = '1';
}else if(i+1<n && i-1>=0 && s[i]==s[i-1] &&s[i]==s[i+1] && s[i]=='0'){
res++;
s[i] = '1';
}
}
cout<<res<<endl;
}
2023C-在规定时间内获得的最大报酬
思路
贪心策略应该是从后往前考虑时间变化。即时刻t
从T
递减变化到1
。
- 考虑某一个时刻
t
,假设该时刻有m
个可以选择的任务,那么我们会在里面挑出报酬最大的那个任务去完成。 - 在时刻
t-1
,除了剩下的m-1
个任务,还有最晚完成时间K = t-1
的若干个任务(假设数量为p
)需要放在一起考虑,那么此时一共有p+m-1
个任务需要考虑,同样在里面挑出报酬最大的那个任务去完成。
#include<bits/stdc++.h>
using namespace std;
int main(){
int T,n;
cin>>T>>n;
map<int,vector<int>> dic;
int time, val;
priority_queue<int> q;
int res = 0;
int latest_time = -1;
while(n--){
cin>>time>>val;
dic[time].push_back(val);
latest_time = max(time,latest_time);
}
for(int t = latest_time;t>T;t--){
for(auto val:dic[t]){
q.push(val);
}
}
for(int t = T;t>0;t--){
if(dic.count(t)){
for(auto val:dic[t]){
q.push(val);
}
}
if(!q.empty()){
res+=q.top();
q.pop();
}
}
cout<<res<<endl;
}
2023C-环中最长子串
解题思路【简单版】
这道题属于带点脑筋急转弯性质的贪心题。乍一看可能会被环型这个条件干扰,把问题想复杂了。
实际上从题目给的几个例子容易分析,如果
- 字符
o
在原字符串中出现的次数为偶数次,为了使得所选子串尽可能长,那么把整个字符串都选上,一定是最长的符合要求的子串。此时子串长度为len(s)
。 - 字符
o
在原字符串中出现的次数为奇数次,为了使得所选子串尽可能长,那么保留一个o
不去选择,那么剩余字符串中o
出现的次数必然为偶数次,把删除一个o
之后的所有字符都选上,一定是最长的符合要求的子串。此时子串长度为len(s)-1
。
因此只需要统计字符o
出现的次数的奇偶性即可。
//吃亏不讨好版
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int n = s.size();
int cnt = count(s.begin(),s.end(),'o');
cnt = cnt%2==0?cnt:cnt-1;
if(cnt == 0){
cout<<n;
return 0;
}
s+=s;
int l=0,r;
int res = 0;
int tmp_cnt = 0;
for(r=0;r<s.size();r++){
if(s[r] == 'o'){
tmp_cnt++;
}
while(tmp_cnt>cnt){
if(s[l] == 'o') tmp_cnt--;
l++;
}
int win = min(n,r-l+1);
if(tmp_cnt == cnt) res = max(res,win);
}
cout<<res;
}
2023C-部门人力分配
#include<bits/stdc++.h>
using namespace std;
// 计算在人力供应为k时,需要最少多少个月才能完成所有需求nums
int check(int k, vector<int>& nums) {
int left = 0, right = nums.size() - 1, ans = 0;
while (left <= right) {
if (nums[left] + nums[right] > k) {
right--;
} else {
left++;
right--;
}
ans++;
}
return ans;
}
int main() {
int m;
cin >> m;
vector<int> nums;
int num;
while (cin >> num) {
nums.push_back(num);
}
sort(nums.begin(), nums.end());
// 设置左闭右开区间:
// 人力供应的最小值为:nums数组中的最大值,否则max(nums)这个工作无法在一个月内完成
// 人力供应的最大值为:nums数组中的两个最大元素相加,
// 这里取一个更加宽松的上限sum(nums),考虑闭区间为sum(nums)+1
int left = *max_element(nums.begin(), nums.end());
int right = accumulate(nums.begin(), nums.end(), 0) + 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (check(mid, nums) <= m) {
right = mid;
} else {
left = mid + 1;
}
}
cout << left << endl;
return 0;
}
2023C-可以组成网络的服务器【DFS/BFS】
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> g;
int max_num = 0;
int res;
int xx[]={0,0,-1,1}, yy[]={1,-1,0,0};
int dfs(int x, int y){
int res = 1;
g[x][y] = 0;
for(int i=0;i<4;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0 && dx<g.size() && dy>=0 && dy<g[i].size() && g[dx][dy] == 1){
res+=dfs(dx,dy);
}
}
return res;
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> mp(n,vector<int>(m));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>mp[i][j];
}
}
g = mp;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]){
res = dfs(i,j);
max_num = max(max_num,res);
}
}
}
cout<<max_num<<endl;
return 0;
}
2023C-图像物体的边界【DFS/BFS】
题解思路
- 先给边界染色
- 再计算边界的个数【等同于计算连通块的个数】
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> g;
int xx[] = {0,0,1,1,1,-1,-1,-1};
int yy[] = {-1,1,-1,0,1,-1,0,1};
void dfs(int x, int y){
g[x][y] = 1;
for(int i=0;i<8;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0 && dx<g.size() && dy>=0 && dy<g[i].size() && g[dx][dy] == -1){
dfs(dx,dy);
}
}
}
int main(){
int n,m;
cin>>m>>n;
vector<vector<int>> mp(m,vector<int>(n));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>mp[i][j];
}
}
g = mp;
for(int x=0;x<m;x++){
for(int y=0;y<n;y++){
if(g[x][y] == 5){
// 给岛屿的边界染色
for(int i=0;i<8;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0 && dx<m && dy>=0 && dy<n && g[dx][dy] == 1){
g[dx][dy] = -1;
}
}
}
}
}
int res = 0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(g[i][j] == -1){
dfs(i,j);
res++;
}
}
}
cout<<res<<endl;
return 0;
}
2023C-地图寻宝【DFS/BFS】
- 数位和:一个数的每一位之和
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> g;
int xx[] = {0,0,1,-1};
int yy[] = {-1,1,0,0};
bool check(int x,int y,int k){
string s1 = to_string(x);
string s2 = to_string(y);
int res = 0;
for(int i=0;i<s1.size();i++) res+=(s1[i] - '0');
for(int i=0;i<s2.size();i++) res+=(s2[i] - '0');
return res<=k;
}
void dfs(int x, int y, int k){
g[x][y] = 0;
for(int i=0;i<4;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0 && dx<g.size() && dy>=0 && dy<g[i].size() && g[dx][dy] == 1 && check(dx,dy,k)){
dfs(dx,dy,k);
}
}
}
int main(){
int n,m,k;
cin>>m>>n>>k;
vector<vector<int>> mp(m,vector<int>(n,1));
g = mp;
for(int x=0;x<m;x++){
for(int y=0;y<n;y++){
if(g[x][y] && x+y<=k){
dfs(x,y,k);
}
}
}
int res = 0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(g[i][j] == 0) res++;
}
}
cout<<res<<endl;
return 0;
}
2023C-跳马问题
#include<bits/stdc++.h>
using namespace std;
const vector<pair<int, int>> DIRECTIONS = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
vector<vector<int>> bfs4SingleHorse(int i, int j, int m, int n, int step) {
vector<vector<int>> mat(m, vector<int>(n, -1));
mat[i][j] = 0;
queue<pair<int, int>> q;
q.push({i, j});
int level = 0;
while (!q.empty()) {
level++;
if (level > step) {
break;
}
int qSize = q.size();
for (int k = 0; k < qSize; k++) {
pair<int, int> cur = q.front();
q.pop();
for (auto &dir : DIRECTIONS) {
int ni = cur.first + dir.first;
int nj = cur.second + dir.second;
if (0 <= ni && ni < m && 0 <= nj && nj < n && mat[ni][nj] == -1) {
mat[ni][nj] = level;
q.push({ni, nj});
}
}
}
}
return mat;
}
int main() {
int m, n;
cin >> m >> n;
cin.ignore();
vector<vector<string>> grid(m, vector<string>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cin >> grid[i][j];
}
}
vector<vector<int>> ansMat(m, vector<int>(n, 0));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] != ".") {
auto mat = bfs4SingleHorse(i, j, m, n, stoi(grid[i][j]));
for (int x = 0; x < m; x++) {
for (int y = 0; y < n; y++) {
if (mat[x][y] == -1 || ansMat[x][y] == -1) {
ansMat[x][y] = -1;
} else {
ansMat[x][y] += mat[x][y];
}
}
}
}
}
}
int ans = INT_MAX;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (ansMat[i][j] != -1 && ans > ansMat[i][j]) {
ans = ansMat[i][j];
}
}
}
cout << ((ans == INT_MAX) ? 0 : ans) << endl;
return 0;
}
2023C-周末爬山
#include<bits/stdc++.h>
using namespace std;
int xx[]={0,0,1,-1},yy[]={1,-1,0,0};
int main(){
int m,n,k;
cin>>m>>n>>k;
vector<vector<int>> mp(m,vector<int>(n));
vector<vector<int>> vis(m,vector<int>(n,0));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>mp[i][j];
}
}
queue<pair<int,int>> q;
q.push({0,0});
vector<pair<int,int>> res;
int steps = 0;
int flag = 0;
int res_hight = mp[0][0];
int res_steps = 0;
vis[0][0] = 1;
while(!q.empty()){
int num = q.size();
steps++;
while(num--){
auto t = q.front();
q.pop();
int x = t.first;
int y = t.second;
for(int i=0;i<4;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0&&dx<m&&dy>=0&&dy<n&&!vis[dx][dy]&&abs(mp[dx][dy]-mp[x][y])<=k){
if(mp[dx][dy]>res_hight){
res_hight = mp[dx][dy];
res_steps = steps;
}
q.push({dx,dy});
vis[dx][dy] = 1;
}
}
}
}
cout<<res_hight<<' '<<res_steps<<endl;
return 0;
}
2023C-堆内存申请
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
vector<int> vis(N);
struct ST{
int s;
int e;
int len;
};
int main(){
//期望申请的内存字节数
int n;
cin>>n;
int x,y;
while(cin>>x>>y){
//判定非法输入
if(x<0||x>=100||y<=0||x+y>=100){
cout<<-1;
return 0;
}
for(int i=x;i<x+y;i++){
if(vis[i] == 1){
cout<<-1;
return 0;
}
vis[i] = 1;
}
}
vector<ST> v;
for(int i=0;i<N;i++){
if(vis[i] == 0){
int x = i,y;
int j = i;
while(j<N && vis[j] == 0){
y = j;
j++;
}
int len = y-x+1;
v.push_back({x,y,len});
i = j-1;
}
}
sort(v.begin(),v.end(),[](ST st1, ST st2){
if(st1.len == st2.len){
return st1.s<st2.s;
}else return st1.len < st2.len;
});
for(auto x:v){
if(x.len>=n){
cout<<x.s;
return 0;
}
}
cout<<-1;
}
2023C-找到它【回溯】
#include<bits/stdc++.h>
using namespace std;
int n,m;
string s;
int xx[]={0,0,1,-1},yy[]={1,-1,0,0};
bool isFind = false;
void dfs(vector<vector<char>>& mp, vector<vector<bool>>& vis, int x, int y, int index){
if(index == s.size()-1){
isFind = true;
return;
}
for(int i=0;i<4;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0 && dx<n && dy>=0 && dy<m && !vis[dx][dy] && mp[dx][dy] == s[index+1]){
vis[dx][dy] = true;
dfs(mp,vis,dx,dy,index+1);
vis[dx][dy] = false;
}
}
}
int main(){
cin>>n>>m;
getchar();
getline(cin,s);
vector<vector<char>> mp(n,vector<char>(m));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>mp[i][j];
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp[i][j] == s[0]){
//vis放在里面,否则在下一个起始点不会对vis进行初始化
vector<vector<bool>> vis(n,vector<bool>(m,false));
vis[i][j] = true;
dfs(mp,vis,i,j,0);
if(isFind){
cout<<i+1<<' '<<j+1<<endl;
return 0;
}
}
}
}
cout<<"NO"<<endl;
return 0;
}
2023C-考古学家【回溯】
#include<bits/stdc++.h>
using namespace std;
vector<string> subset;
set<string> sets;
void dfs(vector<string> v, vector<bool>& vis){
if(subset.size() == v.size()){
string s = "";
for(auto x:subset){
s+=x;
}
sets.insert(s);
return ;
}
for(int i=0;i<v.size();i++){
if(!vis[i]){
if(i && v[i] == v[i-1] && !vis[i-1]) continue;
vis[i] = true;
subset.push_back(v[i]);
dfs(v,vis);
vis[i] = false;
subset.pop_back();
}
}
}
int main(){
int n;
cin>>n;
vector<string> v(n);
for(int i=0;i<n;i++) cin>>v[i];
sort(v.begin(),v.end());
vector<bool> vis(n,false);
dfs(v,vis);
for(auto subset:sets){
for(auto s:subset) cout<<s;
cout<<endl;
}
}
2023C-最长连续手牌【回溯】
#include<bits/stdc++.h>
using namespace std;
int res = 0;
void dfs(vector<pair<int,string>> v,vector<bool>& vis, int i,int len){
res = max(res,len);
for(int j=0;j<v.size();j++){
if(vis[j]) continue;
if(v[i].first == v[j].first || v[i].second == v[j].second){
vis[j] = true;
dfs(v,vis,j,len+1);
vis[j] = false;
}
}
}
int main(){
vector<int> num;
vector<string> color;
string s_num;
getline(cin,s_num);
istringstream is(s_num);
string buffer_num;
while(getline(is,buffer_num,' ')){
num.push_back(stoi(buffer_num));
}
string s_color;
getline(cin,s_color);
istringstream ss(s_color);
string buffer_color;
while(getline(ss,buffer_color,' ')){
color.push_back(buffer_color);
}
vector<pair<int,string>> v;
int n = num.size();
vector<bool> vis(n,false);
for(int i=0;i<n;i++){
v.push_back({num[i],color[i]});
}
for(int i=0;i<n;i++){
vis[i] = true;
dfs(v,vis,i,1);
vis[i] = false;
}
cout<<res<<endl;
}
2023C-寻找最优的路测线路【BFS】
#include<bits/stdc++.h>
using namespace std;
int xx[]={0,0,1,-1},yy[]={1,-1,0,0};
int res = INT_MAX;
struct ST{
int x;
int y;
int val;
// 重载 < 就是重写 sort 的规则
bool operator<(const ST& other) const {
return other.val > val; //降序
}
};
int main(){
int m,n;
cin>>m>>n;
vector<vector<int>> mp(m,vector<int>(n));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>mp[i][j];
}
}
vector<vector<int>> vis(m,vector<int>(n,false));
//在搜索过程中,每次出队的节点不再是按照入队先后顺序弹出的,而是按照最大值作为优先级来弹出的。
//显然以某种优先级作为出队依据,应该使用优先队列来代替队列。
priority_queue<ST> q;
q.push({0,0,mp[0][0]});
vis[0][0] = true;
while(!q.empty()){
auto t = q.top();
q.pop();
int x = t.x;
int y = t.y;
res = min(res,mp[x][y]);
if(x == m-1 && y == n-1) break;
for(int i=0;i<4;i++){
int dx = x + xx[i];
int dy = y + yy[i];
if(dx>=0&&dx<m&&dy>=0&&dy<n&&!vis[dx][dy]){
vis[dx][dy] = true;
q.push({dx,dy,mp[dx][dy]});
}
}
}
cout<<res<<endl;
}
2023C-查找一个有向网络的头节点和尾节点【BFS】
#include<bits/stdc++.h>
using namespace std;
//输出一行头节点和尾节点。
//如果有多个尾节点,按从小到大的顺序输出。
int main(){
int n;
cin>>n;
map<int,int> cnt;
map<int,vector<int>> mp;
set<int> st;
for(int i=0;i<n;i++){
int x,y;
cin>>x>>y;
// 建立邻接表
mp[x].push_back(y);
// 计算该点的入度
cnt[y]++;
// 压入点
st.insert(x);
st.insert(y);
}
queue<int> q;
// 压入入度为 0 的点
// 记录起始点
int first = -1;
for(auto dot:st){
if(cnt[dot] == 0){
first = dot;
q.push(dot);
}
}
vector<int> res;
//用于记录已经访问过的点
set<int> st_vis;
while(!q.empty()){
auto t = q.front();
st_vis.insert(t);
if(mp[t].size() == 0) res.push_back(t);
q.pop();
for(auto x:mp[t]){
cnt[x]--;
if(cnt[x] == 0) q.push(x);
}
}
if(st.size()!=st_vis.size()){
cout<<-1;
return 0;
}
sort(res.begin(),res.end());
cout<<first<<' ';
for(auto x:res) cout<<x<<' ';
}
2023C-通过软盘拷贝文件【DP】
#include<bits/stdc++.h>
using namespace std;
// 输出科学家最多能拷贝的文件总大小【背包问题】
// 一共 2880 个块
// 有若干个文件,每个文件占用 blocks 的空间,价值是 val
// 问最多能获得多少价值
const int amount = 1474560;
const int block = 512;
const int capacity = 2880;
int main(){
int n;
cin>>n;
vector<pair<int,int>> file;
for(int i=0;i<n;i++){
int val;
cin>>val;
int blocks = ceil(float(val)/block);
file.push_back({val,blocks});
}
//记录容量为某一个值时,能获得的最大的价值
vector<int> dp(capacity+1);
for(int i=0;i<n;i++){
for(int j=capacity;j>=file[i].second;j--){
dp[j] = max(dp[j],dp[j-file[i].second]+file[i].first);
}
}
cout<<dp[capacity]<<endl;
}