1. 问题

编程之美1.7光影切割问题可以概括为:

设有两条完全相同的垂直方向上的两条长度相同的线段a和b,且它们对应的端点在同一水平线上。

      已知:在这两条线段之间存在n条线段,且每条线段的起点都在线段a上,终点在线段b上。

      求:这n条线段将线段a和b构成的矩形平面分割成的块数B。

2. 求解

方法一:不难发现B = n + 1 + i,其中i表示图中直线交点的个数。因此该问题就转化为求直线交点个数的问题。

方法二:更为巧妙,进一步将问题转化为求逆序数问题。但书中没有给出如何求解逆序数。

3. 求逆序数

3.1构造测试数据集

以下为我用于产生测试数据的代码,共差生9999个随机整数。值得注意的是该数据集中存在相同的元素,在求解逆序数时应特别注意。产生的随机数将存储到文件dataSource.txt中。

<span style="font-size:14px;">#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
using namespace std;#define DATANUM 9999int main()
{int i = 0;int temp;srand((unsigned)time(NULL));ofstream fin("dataSource.txt");for (i=0; i<DATANUM; ++i){temp = rand()%99999;fin<<temp<<endl;}fin.close();return 0;
}
</span>

3.2问题分析

以下部分纯属个人理解,如有不正确欢迎大家指正。

一个数的逆序数为在它后边比它小的数据的个数。如有序列3、1,对数据3来说后边只有一个1比它小,因此它的逆序数为1;而对于1来说后边没有数据,则它的逆序数为0。

      仔细分析后不难发现一个数串所有逆序数之和与排序时数据交换的次数相同(按照从小到大的顺序排列)。例如有序列3、2、1,用冒泡排序需要交换3次,明显与该序列的逆序数相等。

实际上选择枢纽为2的快排,只需交换了一次。简单分析可得:快速排序没有进行1和3的比较,而逆序数需要考虑任何两个数字之间的关系。因此快速排序不可用,且不稳定的排序算法也是不可用的,因为他们会交换相同数字之间的位置。另外逆序数可以用分支法来求解,即归并算法。以下为用冒泡排序和归并排序求解逆序数的实现。

<span style="font-size:14px;">#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;#define MAXNUM 9999
#define MAXNUMlENGTH 10void readData(int sourceData[MAXNUM]);
int bubbleSort(int sourceData[MAXNUM]);
int merge(int sourceData[MAXNUM], const int lStart, const int lEnd, const int rStart, const int rEnd);
int mergesort(int sourceData[MAXNUM], int begin, int end);
void output(int sourceData[MAXNUM]);int main()
{int sourceData[MAXNUM];readData(sourceData);int choice = 0;int flag = 1;while (flag){cout<<"Run BullSort, please input 0"<<endl;cout<<"Run MergeSort, please input 1"<<endl;cin>>choice;switch (choice){case 0:flag = 0;cout<<"BullleSort result: ";cout<<bubbleSort(sourceData)<<endl;break;case 1:flag = 0;cout<<"Merge result: ";cout<<mergesort(sourceData, 0, MAXNUM-1)<<endl;break;default:break;}}return 0;
}void readData(int sourceData[MAXNUM])
{ifstream fin("dataSource.txt");if (!fin){cout<<"Can't Open the File:"<<endl;exit(1) ;}int i = 0;char tempc[MAXNUMlENGTH];while (fin>>tempc){sourceData[i++] = atoi(tempc);}fin.close();
}//ascending
int bubbleSort(int sourceData[MAXNUM])
{int exchangeTime = 0;int temp = 0;for (int i=0; i<MAXNUM; ++i){for (int j=1; j<MAXNUM-i; ++j){if (sourceData[j-1]>sourceData[j]){temp = sourceData[j-1];sourceData[j-1] = sourceData[j];sourceData[j] = temp;exchangeTime++;}}}return exchangeTime;
}void output(int sourceData[MAXNUM])
{for (int i=0; i<MAXNUM; ++i){cout<<sourceData[i]<<"  ";if (4 == i%5)cout<<endl;}
}int merge(int sourceData[MAXNUM], const int lStart, const int lEnd, const int rStart, const int rEnd)
{int exchangeTime = 0;int tempData[MAXNUM];int templStart = lStart;int templEnd = lEnd;int temprStart = rStart;int temprEnd = rEnd;int i = lStart;while (templStart<=templEnd && temprStart<=temprEnd){if (sourceData[templStart]<=sourceData[temprStart]){tempData[i++] = sourceData[templStart++];//没有交换}else{tempData[i++] = sourceData[temprStart++];//发生交换exchangeTime = exchangeTime + templEnd - templStart + 1;//注意理解}}for ( ; templStart<=templEnd; ++templStart){tempData[i++] = sourceData[templStart];}for ( ; temprStart<=temprEnd; ++temprStart){tempData[i++] = sourceData[temprStart];}for (int j=lStart; j<i; ++j){sourceData[j] = tempData[j];}cout<< lStart<<" "<<lEnd<<" "<<rStart<<" "<<rEnd<<":"<<exchangeTime<<endl;return exchangeTime;
}int mergesort(int sourceData[MAXNUM], int begin, int end)
{if (begin == end)return 0;else{int mid = (begin + end)>>1;return mergesort(sourceData, begin, mid) + mergesort(sourceData, mid+1, end) + merge(sourceData, begin, mid, mid+1, end);}
}</span>

光影切割问题之求解逆序数相关推荐

  1. 归并算法经典应用——求解逆序数

    本文始发于个人公众号:TechFlow,原创不易,求个关注 在之前介绍线性代数行列式计算公式的时候,我们曾经介绍过逆序数:我们在列举出行列式的每一项之后,需要通过逆序数来确定这一项符号的正负性.如果有 ...

  2. 【Algorithm】逆序数的分治求解

    逆序数的分治求解,时间复杂度O(nlgn).基本思想是在归并排序的基础上加逆序计数. 1 #include <iostream> 2 #include <cstdio> 3 # ...

  3. 逆序数问题,用归并排序而非树状数组求解

    逆序数,结合归并排序. 之前一直用树状数组写的,今天发现归并排序也很好写. https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0e ...

  4. 递归/归并:count of smaller numbers求逆序数

    已知数组nums,求新数组count,count[i]代表了在nums[i]右侧且比 nums[i]小的元素个数. 例如: nums = [5, 2, 6, 1], count = [2, 1, 1, ...

  5. 逆序数2 HDOJ 1394 Minimum Inversion Number

    题目传送门 1 /* 2 求逆序数的四种方法 3 */ 1 /* 2 1. O(n^2) 暴力+递推 法:如果求出第一种情况的逆序列,其他的可以通过递推来搞出来,一开始是t[1],t[2],t[3]. ...

  6. 逆序数问题(归并排序,C++)

    在求解八数码问题时,因为要进行逆序数的计算判断两个结点的可达性,同奇偶的逆序数才能可达.如果只是八数,暴力解法还好,当数字多了之后如何知道逆序数呢. 题目描述 通过计算八数码节点的逆序数判断.如果一对 ...

  7. LeetCode 315. 计算右侧小于当前元素的个数(二叉查找树二分查找归并排序逆序数总结)

    文章目录 1. 题目 2. 解题 2.1 二叉查找树 2.2 二分插入 2.3 归并排序 1. 题目 给定一个整数数组 nums,按要求返回一个新数组 counts.数组 counts 有该性质: c ...

  8. POJ 1804 逆序数 解题(归并排序)

    文章目录 解法1:直接双重循环求解,n*n复杂度 解法2:采用归并排序求解,复杂度nlgn 题目链接 http://poj.org/problem?id=1804 题目大意: 让一串无序数,在只能相邻 ...

  9. 高级排序求逆序数之分治法

    前面几篇文章都有讲分治法,分而治之,一种很典型的算法思想,现在求逆序数,如果是你初次接触,一般都会想到冒泡法来统计逆序数.不过冒泡法的时间复杂度确实高(n²),所以接下来运用分治法来实现,复杂度为(n ...

最新文章

  1. 线性回归之正则化线性模型
  2. ASP.NET MVC开发微信(四)
  3. ffmpeg支持x264插件
  4. Ubuntu 16.04 LTS, 64bit,cuda 8, Caffe环境配置编译和安装
  5. instanceof关键字
  6. 阿里云日志添加要查询字段
  7. wampserver的phpmyadmin(默认3306)端口如何更改为3307?
  8. 什么!卷积要旋转180度?!
  9. init.d文件夹 2012-02-09
  10. C语言实现简单学籍管理系统
  11. 基于Modbus TCP-IP协议的WEINVIEW HMI与PC通讯
  12. Vue-组件之间的数据共享
  13. 恩智浦智能车(CNYouth)
  14. wegame显示密保服务器,wegame英雄联盟怎么选定大区
  15. VSCode python extension loading 终极解决方案
  16. 如何破解已签名JAR包
  17. 前端笔记1 HTML基础
  18. 求和计算机教案,七年级信息技术《Excel求和》教学设计
  19. C语言之stroke_s()
  20. Mysql:外码约束

热门文章

  1. 自制工具将excel文件批量导入到mongodb
  2. Vue(v-if,v-show,v-for)
  3. SQL:开窗排序,在order by 后加判断条件的作用是什么?
  4. JAVA中的时间大小比较
  5. Impinj携手英特尔推出EPC UHF RFID平台,助力解决方案快速开发
  6. 简单清晰了解B树和B+树
  7. 实现 复制淘宝的口令进入app 进入活动页功能
  8. 如何把Windows 7英文系统转换为中文系统
  9. ip路由追踪命令(Tracert)
  10. 前端方案(时间/图片/PWA/微信公众号/图片前端压缩/动画与过渡/新兴方案/屏幕适配)