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

news2024/10/6 8:22:48

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

逆序对

题目描述

完整代码

#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;
    }
    else
      tmp[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 part
  int 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 way
  for(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 number
    return 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;
  else
    return 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 tile

void 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 placed

  if (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 corner
  if (specialX >= x + half && specialY < y + half) { // in the bottom-left corner
    tileBoard(board, x + half, y, specialX, specialY, half); // find the bottom-left corner
  } else { // special block is not in the bottom-left corner
    board[x + half][y + half - 1] = currentTile; // put current tile in BL corner
    tileBoard(board, x + half, y, x + half, y + half - 1, half); // find the bottom-left corner
  }

  // bottom-right corner
  if (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 offset
  board[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;
    else
      return 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.coloradmin.cn/o/1038733.html

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

相关文章

【李沐深度学习笔记】线性回归

课程地址和说明 线性回归p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性回归 如何在美国买房&#xff08;经典买房预测问题&#xff09; 一个简化的模型 线性模型 其中&#xff0c; x → [ x 1 , x 2 ,…

如何精细化管理APP用户生命周期,寻找业绩增长点?

在APP精细化运营中&#xff0c;经常会提到用户生命周期&#xff0c;在对APP进行运营的时候&#xff0c;需要明确&#xff0c;自己的APP是处于产品生命周期的哪一个&#xff0c;然后根据这个生命周期的特点&#xff0c;使用最准确的运营方法。 01、为什么要提升用户生命周期价值…

杭州亚运会吉祥物制作,能给城市3D虚拟数字人定制带来什么启发?

继冬奥顶流“冰墩墩”后&#xff0c;吉祥物“江南忆”作为杭州亚运会吉祥物也火爆出圈&#xff01;从北京亚运会的熊猫“盼盼”、到广州亚运会“五羊”再到如今的杭州亚运会吉祥物“宸宸、琮琮、莲莲”&#xff0c;这些吉祥物凭借其形象火爆出圈&#xff0c;能给城市3D虚拟数字…

腾讯mini项目-【指标监控服务重构】2023-08-25

今日已办 traefik proxy jaeger Prometheus prometheus | Prometheus 配置完依然无法实现 web-url的前缀访问【待解决】 Set span storage type : elasticsearch services:elasticsearch:image: elasticsearch:7.17.12container_name: elasticsearchnetworks:- backend # …

String的增删查【C++】

String的增删查【C】 前言string的增删查改构造与析构构造string(const char* str "")赋值构造string(const string& s1) 赋值重载析构函数增reservepush_backappendinsert 删erase 查迭代器流插入流提取流插入流提取 前言 从这里开始可以算是进入了STL的学习中…

火山引擎DataLeap推出两款大模型应用: 对话式检索与开发 打破代码语言屏障

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 自上世50年代&#xff0c;以“计算机”作为代表性象征的信息革命开始&#xff0c;社会对于先进生产力的认知便开始逐步更迭——从信息化&#xff08;通常认为是把企…

kafka latest 模式消费偏移丢数据

Flink消费kafka&#xff0c;这种情况会丢数据

Vue.js 2 —组件(Component)化编程

一、模块与组件 模块 1. 理解 : 向外提供特定功能的 js 程序, 一般就是一个 js 文件 2. 为什么 : js 文件很多&#xff0c;很复杂 3. 作用 : 复用 js, 简化 js 的编写, 提高 js 运行效率 组件 组件是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素&#xff0c;封装…

在呼叫中心领域,人工智能目前处在什么阶段

在呼叫中心这个行业&#xff0c;人工智能已经逐渐走向实用化阶段。目前&#xff0c;很多企业已经开始采用人工智能技术来改善其呼叫中心的效率和服务质量。 具体来说&#xff0c;人工智能已经被用于呼叫中心自动语音应答、自然语言处理、智能路由、智能客服机器人等方面。通过这…

机器学习中的分类问题:如何选择和理解性能衡量标准

文章目录 &#x1f34b;引言&#x1f34b;为什么需要分类问题的性能衡量标准&#xff1f;&#x1f34b;常用的分类问题衡量标准&#x1f34b;混淆矩阵-精确率-召回率&#x1f34b;PR曲线和ROC曲线&#x1f34b;PR曲线&#x1f34b;ROC曲线&#x1f34b;PR vs. ROC &#x1f34b…

外汇天眼:外汇新手开展交易需要做哪些准备,你都知道么?

外汇交易&#xff0c;如同任何一项专业工作&#xff0c;需要不断积累知识和经验&#xff0c;以及稳定的心态。正如古语所说&#xff1a;“工欲善其事&#xff0c;必先利其器。” 在外汇市场&#xff0c;这句话同样适用。在踏上外汇交易之旅之前&#xff0c;我们迫切需要做好外汇…

Windows清除激活标志的方法

大家在购买电脑或笔记本的时候&#xff0c;有的商家给出的7天无理由退货&#xff0c;并不是真正的无理由&#xff0c;往往附件条件windows是不能激活的&#xff0c;如果激活了就只能换不能退了。 卖家提出的条件也特别滑稽可笑&#xff0c;你想不联网怎么体验啊&#xff1f;不…

一百八十五、大数据离线数仓完整流程——步骤四、在Hive的DWD层建动态分区表并动态加载数据

一、目的 经过6个月的奋斗&#xff0c;项目的离线数仓部分终于可以上线了&#xff0c;因此整理一下离线数仓的整个流程&#xff0c;既是大家提供一个案例经验&#xff0c;也是对自己近半年的工作进行一个总结。 二、数仓实施步骤 &#xff08;四&#xff09;步骤四、在Hive的…

最新Python大数据之Excel进阶

文章目录 Excel图表类型了解有哪些图表类型 Excel图表使用图表的创建方式利用固定数据区域创建图表编辑数据系列添加数据标签格式化图表 Excel数据透视表数据透视表对原始数据的要求创建数据透视表数据透视表字段布局将数据透视图变成普通图表 Excel图表类型 为了揭示数据规律…

入门级制作电子期刊的网站推荐

随着数字化时代的到来&#xff0c;越来越多的人开始尝试制作自己的电子期刊。如果你也是其中的一员&#xff0c;那么这篇文章可以帮助你制作电子期刊。无论是初学者还是有一定经验的制作者&#xff0c;都能快速完成高质量的电子期刊制作 小编经常使用的工具是-----FLBOOK在线制…

Python爬虫在Web应用自动化测试中的应用

在Web应用开发过程中&#xff0c;自动化测试是确保应用质量和稳定性的重要环节。本文将介绍如何使用Python爬虫与自动化测试技术相结合&#xff0c;实现对Web应用进行自动化测试的方法和步骤。通过这种结合&#xff0c;我们可以提高测试效率、减少人力成本&#xff0c;并确保应…

RocketMQ 消息重试机制

文章目录 消息发送重试重试触发条件重试流程重试间隔重试常见问题消息流控机制流控触发条件 生产者控制消息发送重试次数gRPC 客户端remoting 客户端 消费重试重试触发条件PushConsumer 消费重试策略PushConsumer 重试间隔时间修改 PushConsumer 最大重试次数gRPC 协议端口Remo…

华为数字能源,开启超充新纪元

编辑&#xff1a;阿冒 设计&#xff1a;沐由 在过去很长的一段时间里&#xff0c;国内某著名品牌火锅是从来不担心获客的。顶峰时期&#xff0c;该品牌每年服务超过1.6亿人次的顾客&#xff0c;翻台率达到了5次/天&#xff0c;几乎创下了餐饮界的最高翻台率。 翻台率是餐饮企业…

调用CFCA金信反欺诈服务相关接口,很详细

调用CFCA金信反欺诈服务相关接口&#xff0c;很详细 一、准备二、调用接口1、查询接口文档2、查看代码示例3、测试调用接口 三、工具类1、CFCA金信反欺诈服务接口码枚举类2、CFCA金信反欺诈服务的公共参数配置3、加密解密工具类4、请求参数dto5、调用接口工具类&#xff08;关键…

【N年测试总结】证券行业的测试特点

每个行业由于其业务形式&#xff0c;产品形态&#xff0c;行业要求等等的不同&#xff0c;都有其不同于其他行业的测试特点&#xff0c;对测试人员的重点能力要求也不同。 一、证券行业业务系统简介 证券行业的业务系统这里按照C端系统和B端业务系统两大类进行介绍。 C端系统…