DS实验题 Inversion
题目:

解题过程:
第一次做这题的时候,很自然的想到了冒泡和选择,我交的代码是用选择写的。基本全WA(摊手)。
贴上第一次的代码:
//
// main.cpp
// sequenceschange
//
// Created by wasdns on 16/10/7.
// Copyright ? 2016年 wasdns. All rights reserved.
//
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;
int seq[50005];
int main() {
int i, j, n;
cin >> n;
for (i = 0; i < n; i++) {
cin >> seq[i];
}
int cnt = 0;
int t = 0;
for (i = n - 1; i >= 0; i--) {
for (j = i - 1; j >= 0; j--) {
if(seq[i] > seq[j]) break;
cnt ++;
t = seq[i];
seq[i] = seq[j];
seq[j] = t;
}
}
cout << cnt << endl;
return 0;
}
冒泡和选择,这两种算法的问题在于,会有重复比较的元素,不满足题意要求的最小比较次数。
本题也是比较经典的逆序对问题,解决的方法是插入排序。
这里给出链接参考:九大排序算法再总结
第二种算法(分治加插入排序)思想:
给出一个数组,以及给出左边界l右边界r代表需要排序的序列范围,将这个序列不断分成两个部分,直到递归到单个元素再向上进行Union的操作,Union的操作通过插入排序来实现。
//
// main.cpp
// 逆序对
//
// Created by wasdns on 16/12/1.
// Copyright © 2016年 wasdns. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[50010];
/*
用来debug的函数
*/
void printa(int l, int r)
{
for (int i = l; i <= r; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
/*
交换函数
*/
void swap(int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
/*
Union 两部分合并函数
*/
int Union(int l, int r)
{
if (l == r) return 0;
int i, p1, p2; //p1指向序列A的元素,p2指向序列B的元素
int cnt = 0; //记录比较次数
for (i = l+1; i <= r; i++)
{
p1 = i-1;
p2 = i;
while (a[p2] < a[p1] && p1 != 0)
{
swap(p1, p2);
cnt++;
p1--;
p2--;
}
}
return cnt;
}
/*
排序算法主体
*/
int divsort(int l, int r)
{
//printf("div:");
//printa(l, r);
if (l == r) return 0;
int cnt = 0;
int mid = (l+r) / 2;
int ltime = divsort(l, mid);
int rtime = divsort(mid+1, r);
cnt += ltime;
cnt += rtime;
cnt += Union(l, r);
//printf("afterdiv:");
//printa(l, r);
return cnt;
}
void Initial(int n)
{
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
}
int main()
{
int n;
cin >> n;
Initial(n);
int cnt;
cnt = divsort(1, n);
printf("%d\n", cnt);
return 0;
}
结果是部分点TLE:

分析下算法复杂度:选择最后一次的Union操作,最坏情况下一共有50000个节点,从l到mid是25000个排好序的元素,从mid开始到r有25000个无序的元素,将后面的25000个元素插入到前面的序列,>=25000*25000的时间;复杂度为O(n^2),因此TLE。
于是选择使用归并排序,之前的操作和算法二的思想类似,但是修改了Union的操作:维护一个数组b,使用两个指针指向两个待排序的序列,把这两个指针分别指向的元素进行比较,较小的元素加入到b中,指向它的指针后移,直到到达边界。
另外一个需要care的点是cnt的计数:
倘若先前的序列叫做A,后面的序列叫做B,当判断出B序列的当前指向元素较小进入数组b时,相当于是通过mid+1-p1(p1是当前指针指向A的位置)次比较的操作将元素移至有序的位置。
int Union(int l, int r)
{
if (l == r) return 0;
int mid = (l+r) / 2;
int i, p1 = l, p2 = mid+1;
int cnt = 0;
int tot = 1;
while (p1 <= mid && p2 <= r)
{
if (a[p1] > a[p2]) {
cnt += mid+1-p1; //相当于比较了mid+1-p1次
b[tot++] = a[p2++];
}
else b[tot++] = a[p1++];
}
if (p1 > mid && p2 <= r)
{
while (p2 <= r)
{
b[tot++] = a[p2++];
}
}
else if (p2 > r && p1 <= mid)
{
while (p1 <= mid)
{
b[tot++] = a[p1++];
}
}
for (i = l; i <= r; i++)
{
a[i] = b[i-l+1];
}
return cnt;
}
int divsort(int l, int r)
{
//printf("div:");
//printa(l, r);
if (l == r) return 0;
int cnt = 0;
int mid = (l+r) / 2;
int ltime = divsort(l, mid);
int rtime = divsort(mid+1, r);
cnt += ltime;
cnt += rtime;
cnt += Union(l, r);
//printf("afterdiv:");
//printa(l, r);
return cnt;
}
算法复杂度:O(n)
2016/12/2
DS实验题 Inversion的更多相关文章
- DS实验题 融合软泥怪-2 Heap实现
题目和STL实现:DS实验题 融合软泥怪-1 用堆实现优先队列 引言和堆的介绍摘自:Priority Queue(Heaps)--优先队列(堆) 引言: 优先队列是一个至少能够提供插入(Insert) ...
- DS实验题 Old_Driver UnionFindSet结构 指针实现邻接表存储
题目见前文:DS实验题 Old_Driver UnionFindSet结构 这里使用邻接表存储敌人之间的关系,邻接表用指针实现: // // main.cpp // Old_Driver3 // // ...
- DS实验题 Dijkstra算法
参考:Dijkstra算法 数据结构来到了图论这一章节,网络中的路由算法基本都和图论相关.于是在拿到DS的实验题的时候,决定看下久负盛名的Dijkstra算法. Dijkstra的经典应用是开放最短路 ...
- DS实验题 sights
算法与数据结构实验题 6.3 sights ★实验任务 美丽的小风姑娘打算去旅游散心,她走进了一座山,发现这座山有 n 个景点, 由于山路难修,所以施工队只修了最少条的路,来保证 n 个景点联通,娇弱 ...
- DS实验题 order
算法与数据结构 实验题 6.4 order ★实验任务 给出一棵二叉树的中序遍历和每个节点的父节点,求这棵二叉树的先序和后序遍历. ★数据输入 输入第一行为一个正整数n表示二叉树的节点数目,节点编号从 ...
- DS实验题 Order 已知父节点和中序遍历求前、后序
题目: 思路: 这题是比较典型的树的遍历问题,思路就是将中序遍历作为位置的判断依据,假设有个节点A和它的父亲Afa,那么如果A和Afa的顺序在中序遍历中是先A后Afa,则A是Afa的左儿子,否则是右儿 ...
- DS实验题 Missile
题目: 提示:并没有精度问题. 原题 NOIP2010 导弹拦截 思路 设源点为A(x1, y1)和B(x2, y2). 第一步,用结构体存节点,包括以下元素: 1.横坐标x 2.纵坐标y 3.节点和 ...
- DS实验题 击鼓传花
题目: 代码1(数组实现): // // main.cpp // DS-击鼓传花 // // Created by wasdns on 16/11/9. // Copyright © 2016年 wa ...
- DS实验题 地鼠安家
★实验任务 fd是一个公认的美丽校园.一天,fd来了一群地鼠,编号为1到n,他们希望在这里定居.现在先由第一只地鼠往下打一个单位的距离,并且在那里安家.对于每一个已经安家的地鼠,如果他左下或右下没有邻 ...
随机推荐
- 归并排序的分析与Java实现
归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作.归并排序算法依赖归并操作.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.归并排序 ...
- oracle 10g 学习之PL/SQL简介和简单使用(10)
PL /SQL是一种高级数据库程序设计语言,该语言专门用于在各种环境下对ORACLE数据库进行访问.由于该语言集成于数据库服务器中,所以PL/SQL代码可以对数据进行快速高效的处理.PL/SQL是 P ...
- String.split使用竖线做为分隔符
String.split使用竖线做为分隔符时会发现得到的数组不对,每个字符都被拆分成数组里的一个值: 解决办法:竖线需要转义才可以作为split的参数,String.split("\\|&q ...
- c语言 struct 的初始化
转自:http://www.cnblogs.com/silentjesse/archive/2013/07/30/3225212.html struct数据有3中初始化方法:顺序,C风格及C++风格的 ...
- cocos2dx游戏开发——微信打飞机学习笔记(四)——GameScene的搭建
一.创建文件 首先呢,就是那个创建新的.h 和 .cpp 的文件,然后可以起名为GameScene 最重要的就是一定要创建在Classes的目录下哦= =,别手抖= =. 二.GameScene.h和 ...
- JSON浅总
我们在以前的学习中了解到XML是一种结构化的数据表示方式,一种可扩展标记语言!可以把XML理解成一个微型的结构化的小的数据库,保存一些小型的数据和传输数据,有严格的显示限制.但是XML语句有些冗长和繁 ...
- LoadRunner字符串与参数的操作及转换技巧
刚开始学LR时,经常搞不清楚变量和参数的区别与用法,最近在一次脚本编写中,整理出来的一些小技巧,与大家一起分享. //字符串复制 strcpy(str,"Hello ") ; // ...
- 关于C语言中for循环的执行顺序
for(初始值赋值操作A:终止条件B:递增操作C) { 循环体D: } 其执行次序为:A->B->D->C->B->D->C->B--.. 直到B条 ...
- cf 621D
http://acm.zzkun.com/archives/717 这个大神的解答非常,额 猥琐.但是实在是太强了.感觉所有的大数都可以用 long double 了.
- C#二进制与字符串之间的相互转换
1 /// <summary> 2 /// 将字符串转成二进制 3 /// </summary> 4 /// <param name="s">& ...