演算法課7-Divide and Conquer
分治的思想,最經典的兩個例子首先是排序的兩個例子 一個是快排 一個是歸併排序【請看到這裡的你,去複習一下排序演算法】
- 快速排序 先總體再區域性
int partition(int nums[],int left,int right){
int i=left;
int j=right;
int temp=nums[i];
while(i<j){//注意下面內層while的順序
while(i<j && nums[j]>=temp) {j--;}
nums[i]=nums[j];
while (i<j && nums[i]<=temp) {i++;}
nums[j]=nums[i];
}
nums[i]=temp;
return i;
}
void quickSort(int nums[],int left,int right){
if(left<right) {
int p = partition(nums, left, right);
quickSort(nums, left, p - 1);
quickSort(nums, p + 1, right) ;
}
}
- 作業例題 【使用歸併排序】 先區域性再總體,需要一個臨時陣列。
F:求逆序對數 總時間限制: 500ms 記憶體限制: 65536kB
描述 對於一個長度為N的整數序列A,滿足i < j 且 Ai > Aj.的數對(i,j)稱為整數序列A的一個逆序 請求出整數序列A的所有逆序對個數
輸入 輸入包含多組測試資料,每組測試資料有兩行 第一行為整數N(1 <= N <= 20000),當輸入0時結束 第二行為N個整數,表示長為N的整數序列 輸出 每組資料對應一行,輸出逆序對的個數 樣例輸入
5 1 2 3 4 5 5 5 4 3 2 1 1 1 0
樣例輸出
0 10 0
#include<iostream>
#include<string>
#include<string.h>
#include<queue>
#include<functional>
#include<vector>
#include <math.h>
#include <algorithm>
using namespace std;
int n;
int num[20005];
int temp[20005];
int res;
void Merge(int low,int mid,int high){
int i=low;
int j=mid+1;
int tmp=low;
while (i<=mid && j<=high){
if(num[j]<num[i])
{
//如果aj<ai即左邊的小於右邊的,右邊剩下的都可以構成逆序對
res+=mid-i+1;
temp[tmp++]=num[j++];
}
else{
temp[tmp++]=num[i++];
}
}
while (i<=mid) temp[tmp++]=num[i++];
while (j<=high) temp[tmp++]=num[j++];
for(int k=low;k<=high;k++){
num[k]=temp[k];
}
}
void mergesort(int low,int high){
if(low<high){
int mid=(low+high)/2;
mergesort(low,mid);
mergesort(mid+1,high);
Merge(low,mid,high);
}
}
int main(){
while(cin>>n && n){
for(int i=0;i<n;i++){
cin>>num[i];
}
res=0;
mergesort(0,n-1);
cout<<res<<endl;
}
return 0;
}
拓展 重要逆序對 總時間限制: 10000ms 單個測試點時間限制: 1000ms 記憶體限制: 65536kB
描述
給定N個數的序列a1,a2,…aN,定義一個數對(ai, aj)為“重要逆序對”的充要條件為 i < j 且 ai > 2aj。求給定序列中“重要逆序對”的個數。
輸入
第一行為序列中數字的個數N(1 ≤ N ≤ 200000)。 第二行為序列a1, a2 … aN(0 ≤a ≤ 10000000),由空格分開。
輸出
輸出一個整數,為給序列中“重要逆序對”的個數。
樣例輸入
10 0 9 8 7 6 5 4 3 2 1
樣例輸出
16
提示 如果使用printf輸出long long型別,請用%lld資料範圍 對於40%的資料,有N ≤ 1000。
同樣的使用歸併排序,在歸併時先用一個指標掃一次,左邊如果有滿足條件的,那麼它的後面的數字都滿足條件。與上題類似,單看merge。 (注意這題的輸出是long long型別)
void Merge(int low,int mid,int high){
int i=low;
int j=mid+1;
int tmp=low;
int pointer=low;
while (i<=mid && j<=high){
if(num[j]<num[i])
{
while(pointer<=mid && 2*num[j]>=num[pointer]){
pointer++;
}
res+=mid+1-pointer;
// res+=mid-i+1;
temp[tmp++]=num[j++];
}
else{
temp[tmp++]=num[i++];
}
}
while (i<=mid) temp[tmp++]=num[i++];
while (j<=high) temp[tmp++]=num[j++];
for(int k=low;k<=high;k++){
num[k]=temp[k];
}
}
進階版LeetCode 315. Count of Smaller Number After Self 求每個位置元素對應的逆序對,仍可以用歸併排序。 Java merge sort solution 為了保持原陣列不動,需要維護一個index陣列 注意每次從right中移數,rightcount++;從left中移數,把count陣列加上rightcount 如[2,3,4] [1,2,3] 左邊是2的時候,rightcount=1,把2移入,對應2的count加上1。
- 平面最近點對 步驟1:根據點的y值和x值對S中的點排序。 步驟2:找出中線L將S劃分為SL和SR 步驟3:將步驟2遞迴的應用解決SL和SR的最近點對問題,並令d=min(dL,dR)。 步驟4:將L-d ~ L+d內的點以y值排序,對於每一個點(x1,y1)找出y值在y1-d~y1+d內的接下來的7個點,計算距離為d’。如果d’小於d,令d=d’,最後的d值就是答案。 平面最近點對實驗