分治算法求解:逆序对,Max Sum,棋盘覆盖,a-Good String——中山大学软件工程学院算法第四次实验课 必做+选做题

写英文注释不是要“秀英文”,而是因为鄙人正在准备雅思,顺手练习

逆序对

题目描述

完整代码

#include<iostream>
using namespace std;
int num[500010]; // input numbers
int tmp[500010]; // sequence after merging left and right part
long long res;// Count of inversions
void merge(int left,int mid,int right){int i=left,j=mid+1;int idx=0;while(i<=mid&&j<=right){if(num[i]>num[j]){tmp[idx++]=num[j++];res+=mid-i+1;}elsetmp[idx++]=num[i++];}while(i<=mid)tmp[idx++]=num[i++];while(j<=right)tmp[idx++]=num[j++];
}
void merge_sort(int left,int right){if(left>=right){return;}int mid=(left+right)/2;merge_sort(left,mid);merge_sort(mid+1,right);merge(left,mid,right);for(int i=left;i<=right;i++){num[i]=tmp[i-left]; //num数组不是tmp数组翻转过来!//这里是调整索引}
}
int main(){ios::sync_with_stdio(false);int n;cin>>n;for(int i=0;i<n;i++){cin>>num[i];}res=0;merge_sort(0,n-1);cout<<res<<endl;
}

代码讲解 

归并排序。在合并的过程发现逆序的时候,后面有多少个就说明有多少个逆序了。

  for(int i=left;i<=right;i++){num[i]=tmp[i-left]; //num数组不是tmp数组翻转过来!//这里是调整索引}

注意这里的索引调整 i-left 是因为 tmp 数组是从 0 开始的,而 num 数组的相应段是从 left 开始的。

Max Sum

题目描述

完整代码

#include<iostream>
#include<cstring>
using namespace std;
int num[100010];
struct node{int l,r,sum;node(int x,int y,int z):l(x),r(y),sum(z){}//constructor initialization
};
node crossingSubArray(int num[],int mid,int low,int high){node s3(0,0,0);int sum=0;int max_left=-10000;// max value for the left partint max_right=-10000;// max value for the right part// A very sophisticated algorithm. Since this array crosses both the left and right arrays, the middle must be crossed!// For the left part, the sequence starts from the middle and goes to the low index. If there is an index that achieves a larger value, update the left index.for(int i=mid;i>=low;i--){sum+=num[i];if(sum>=max_left){max_left=sum;s3.l=i;}}sum=0;// possess the right array in the same wayfor(int i=mid+1;i<=high;i++){sum+=num[i];if(sum>max_right){max_right=sum;s3.r=i;}}s3.sum=max_left+max_right;return s3;
}
node maxSubArray(int num[],int left,int right){if(left==right){//means that there is only one numberreturn node(left,right,num[left]);}int mid=(left+right)/2;node s1= maxSubArray(num,left,mid);node s2= maxSubArray(num,mid+1,right);node s3= crossingSubArray(num,mid,left,right);if(s1.sum>=s2.sum&&s1.sum>=s3.sum)return s1;else if(s2.sum>=s1.sum&&s2.sum>=s3.sum)return s2;elsereturn s3;
}
int main(){int T,n;ios::sync_with_stdio(false);cin>>T;int ncase=0;while(T--){cin>>n;memset(num,0,sizeof(num));for(int i=0;i<n;i++){cin>>num[i];}node res=maxSubArray(num,0,n-1);if(ncase){//equivalent to if(ncace!=0)cout<<endl;}cout<<"Case "<<++ncase<<":\n";cout<<res.sum<<" "<<res.l+1<<" "<<res.r+1<<endl;}
}

代码讲解

用分治法解决的思路是:

把数组对半分,使得和最大的左和右索引,要么包括了左半边,要么包括了右半边,要么一个在左边,一个在右边。所以在这三个中取最大值即可。如果只在某半边,因为最后会把那个块拆成单个,所以是可以直接通过比较比出来。如果是穿过了中间,注意要从中间往两边增(拆成先往左增再往右增)来比较怎么样才是最大的并且记下来此时的下标。

棋盘覆盖问题

题目描述

完整代码

#include<iostream>
#include<vector>
using namespace std;int tile=1;// index of tilevoid tileBoard(vector<vector<int> >& board,int x,int y,int specialX,int specialY,int size){if(size==1) return;int half=size/2;int currentTile=tile++;// top-left corner// if the special block is in the top-left corner, solve the top-left corner first.// if not, the top-left block among the four in the center can be determined as the place where the current tile should be placedif (specialX < x + half && specialY < y + half) {tileBoard(board, x, y, specialX, specialY, half);} else {board[x + half - 1][y + half - 1] = currentTile;tileBoard(board, x, y, x + half - 1, y + half - 1, half);}if (specialX < x + half && specialY >= y + half) {tileBoard(board, x, y + half, specialX, specialY, half);} else {board[x + half - 1][y + half] = currentTile;tileBoard(board, x, y + half, x + half - 1, y + half, half);}// bottom-left cornerif (specialX >= x + half && specialY < y + half) { // in the bottom-left cornertileBoard(board, x + half, y, specialX, specialY, half); // find the bottom-left corner} else { // special block is not in the bottom-left cornerboard[x + half][y + half - 1] = currentTile; // put current tile in BL cornertileBoard(board, x + half, y, x + half, y + half - 1, half); // find the bottom-left corner}// bottom-right cornerif (specialX >= x + half && specialY >= y + half) {tileBoard(board, x + half, y + half, specialX, specialY, half);} else {board[x + half][y + half] = currentTile;tileBoard(board, x + half, y + half, x + half, y + half, half);}
}
int main(){int k,x,y;cin>>k>>x>>y;int size=(1<<k);vector<vector<int> > board(size,vector<int>(size,0));// a quick way to initialize the 2D vector to 0// The number of dimensions in the vector corresponds to the number of levels of nesting//NOTE:the coordinate offsetboard[x-1][y-1]=0;tileBoard(board,0,0,x-1,y-1,size);for(const auto & row:board){for(int i=0;i<row.size();i++){cout<<row[i]<<(i==row.size()-1?'\n':' '); // A simple but useful judgement}}}//the board look like this
/**   y 0 1 2* x 0 TL TR*   1 BL BR*   2**/

代码讲解

这题的思路还有点绕。就是先把棋盘分成4大块。先看特殊方块在不在左上,如果在的话递归进入左上搜索。如果不在,说明左上最靠近中心(也就是左上大块最右下的小块)标记为当前的骨牌。其余几个同理。

a-Good String

题目描述

完整代码

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string str;
int solve(int left,int right,char c){if(left==right){if(c==str[left])return 0;elsereturn 1;}int mid =(left+right)/2;int res1=0,res2=0;for(int i=left;i<=mid;i++){if(str[i]!=c) {res1++;}}for(int i=mid+1;i<=right;i++){if(str[i]!=c) {res2++;}}return min(res1 + solve(mid + 1, right, c + 1), res2 + solve(left, mid, c + 1));
}
int main(){int T,n;cin>>T;while(T--){cin>>n>>str;cout<<solve(0,n-1,'a')<<endl;}return 0;
}

代码讲解

先拆分。用个solve函数返回当前字符串变多少个能成为good string。退出条件:如果最后只剩一个了,这个是指定的c,那就不用变,为0;否则,要变一个,为1。

然后尝试字符串前一半为a,根据题意,此时如果前一半中有不是a的,要变的次数+1。然后加上递归后一半中要变的。

同理再尝试字符串的后一半为a,根据题意,此时如果后一半中有不是a的,要变的次数+1。然后加上递归前一半中要变的。

最后,返回前后对比变的次数更少的那一个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/141695.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

鼠标不动了怎么办?3招解决问题!

“这是怎么回事呢&#xff1f;我的鼠标怎么会用着用着就突然不动了呢&#xff1f;现在有一些比较重要的工作要处理。请问有什么方法可以快速解决这个问题吗&#xff1f;” 随着电脑在我们日常生活和工作中的广泛应用&#xff0c;鼠标是我们操作电脑不可或缺的工具之一。但是&am…

WebGL 绘制圆形的点

目录 前言 如何实现圆形的点&#xff1f; 片元着色器内置变量&#xff08;gl_FragCoord、gl_PointCoord&#xff09; gl_PointCoord的含义 示例程序&#xff08;RoundedPoint.js&#xff09; 代码详解 前言 本文将讨论示例程序RoundedPoint&#xff0c;该程序绘制了圆…

Spring底层原理之 BeanFactory 与 ApplicationContext

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Spring底层原理 一、 BeanFactory 与 Appli…

爬虫怎么批量采集完成任务

目录 一、了解网络爬虫 二、Python与网络爬虫 三、批量采集任务的实现 1.确定采集网站及关键词 2.安装相关库 3.发送请求并获取响应 4.解析HTML文档 5.提取文章内容 6.保存文章内容 7.循环采集多篇文章 8.增加异常处理机制 9.优化代码性能 四、注意事项 总结 在当…

登录业务实现 - token登录鉴权

登录业务实现&#xff1a; 登录成功/失败实现 -> pinia管理用户数据及数据持久化 -> 不同登录状态的模板适配 -> 请求拦截器携带token&#xff08;登录鉴权&#xff09; -> 退出登录实现 -> token失效&#xff08;401响应拦截&#xff09; 1. 登录成…

(循环)mysql定时器删除某表中数据例子

CREATE EVENT clear_interactive_logs ON SCHEDULE EVERY 1 DAY STARTS 2023-09-21 23:36:36 DO DELETE from t_interactive_log WHERE id not IN (SELECT * from (SELECT id from t_interactive_log ORDER BY occer_time DESC limit 20000) x ); END ———————————…

Java编程的精髓:深入理解JVM和性能优化

文章目录 Java虚拟机&#xff08;JVM&#xff09;的核心概念1. 类加载器&#xff08;Class Loader&#xff09;2. 内存区域3. 垃圾回收&#xff08;Garbage Collection&#xff09;4. 类型转换和多态 JVM性能调优1. JVM参数调整2. 内存管理3. 多线程优化4. 使用性能分析工具5. …

【技术分享】NetLogon于域内提权漏洞(CVE-2020-1472)

一、漏洞介绍 CVE-2020-1472是一个Windows域控中严重的远程权限提升漏洞。攻击者在通过NetLogon&#xff08;MS-NRPC&#xff09;协议与AD域控建立安全通道时&#xff0c;可利用该漏洞将AD域控的计算机账号密码置为空&#xff0c;从而控制域控服务器。该漏洞适用于Win2008及后…

C++:优先级队列模拟实现和仿函数的概念使用

文章目录 使用方法Compare仿函数一些场景模板参数和函数参数 本篇总结优先级队列 使用方法 首先在官网查看它的一些用法 template <class T, class Container vector<T>,class Compare less<typename Container::value_type> > class priority_queue;从…

S09-录入的数据快速分列

选中某一列数据&#xff0c;数据-》分列 确定分隔符

Blender导出FBX给UE5

最近在学习UE5的资源导入&#xff0c;总结如下&#xff1a; 建模使用Blender&#xff0c;UE5版本是5.3 1.纯静态模型导入UE5 Blender FBX导出设置保持默认即可&#xff0c; UE5把导入设置里Miscellaneous下Force Front XAxis和Convert Scene Unit勾选即可 2.带骨骼动画的模型…

命令执行(rce)

1.命令与代码执行原理 命令执行原理 参数给变量未经过滤&#xff0c;直接使用了不安全的函数处理了变量 127.0.0.1&&ipconfig 有漏洞 常用的函数 assert,system,exec,shell_exec, eval,(反单引号&#xff09; 代码执行原理 参数给变量未经过滤&#xff…

Postgresql源码(113)表达式JIT计算简单分析

相关 《Postgresql源码&#xff08;85&#xff09;查询执行——表达式解析器分析&#xff08;select 11如何执行&#xff09;》 《Postgresql源码&#xff08;113&#xff09;表达式JIT计算简单分析》 1 普通表达式计算 普通表达式计算发生在优化器preprocess_expression中&am…

Day1-DeepWalk

论文《DeepWalk: Online Learning of Social Representations》 2014年发表在数据挖掘顶会ACM SIGKDD&#xff08;KDD&#xff09;上的论文 目的&#xff1a;学习节点表示 推动&#xff1a;将自然语言处理里面的无监督学习方法迁移至此 思路&#xff1a;将图结构序列化&#x…

关于安卓SVGA浅尝(二)加载数据

关于安卓SVGA浅尝&#xff08;二&#xff09;加载数据 相关链接 SVGA官网 SVGA-github说明文档 背景 项目开发&#xff0c;都会和动画打交道&#xff0c;动画的方案选取&#xff0c;就有很多选择。如Json动画&#xff0c;svga动画&#xff0c;gif等等。各有各的优势。目前项…

【Linux】系统编程基于环形队列生产者消费者模型(C++)

目录 【1】引入POSIX信号量 【1.1】初始化信号量 【1.2】销毁信号量 【1.3】等待信号量 【1.4】发布信号量 【2】基于环形队列的生产消费模型 【2.1】生产消费模型打印数字模型 【2.2】生产消费模型计算公式模型 【2.3】生产消费模型计算公式加保存任务模型 【1】引入…

React中setState的原理及深层理解

1.为什么使用setState React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化 我们必须通过setState来告知React数据已经发生了变化 setState方法是从Component中继承过来的。 2.setState异步更新 setState设计为异步&#xff0c;可…

深度学习技巧应用28-强化学习的原理介绍与运用技巧实践

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用28-强化学习的原理介绍与运用技巧实践, 强化学习是一种机器学习的子领域,它使得一个智能体在与环境的交互中学习如何行动以最大化某种数值奖励信号。强化学习模型的关键特性是它的试错搜索和延迟奖励。 一、强化学习…

聚势共创 多元共生——中科美菱联动清华大学助力产研融合!

9月23日&#xff0c;由中科美菱首席赞助支持的第十六届清华大学“生命科学、医学、药学”博士生学术论坛在美丽的白洋淀畔——雄安新区拉开序幕。清华大学生物物理学家、中国科学院院士隋森芳、清华大学生命科学学院党委书记吴畏、雄安新区党工委员会委员、管委会副主任丁晓龙、…

Windows下创建后门隐藏用户的常见方法

文章并没有什么技术含量,纯粹是我正好在做这个事情,同时想到自己之前没有写过,所以特意写一遍记录以下 windows 下的后门用户主要分为以下4种。 启用游客用户创建普通用户创建普通隐藏用户创建影子用户 第一种启用游客用户 通过以下命令即可启用Guest用户&#xff0c;该用户是…