알고리즘 설계 및 분석을위한 선형 시간 선택
선형 시간 선택 알고리즘
- 빠른 정렬 알고리즘 모방
- 어레이에서 분할 및 정복 전략 사용
예 1
문제 설명
주어진 n 개 요소 배열 a [0 : n-1]의 경우, 여기에서 k 번째로 작은 요소를 찾아야합니다.
입력 : 여러 테스트 케이스 세트를 입력합니다.
각 테스트 케이스에 대해 2 개의 행이 있으며,
첫 번째 행은 정수 n과 k (1≤k < n≤1000)이고
두 번째 행은 n 정수입니다.
출력 : k 번째로 작은 요소
문제 분석
우리는 일종의 빠른 정렬 알고리즘의 아이디어가
표준으로 숫자를 찾고 왼쪽에 작은 숫자를 놓고 오른쪽에 큰 숫자를 넣는 것입니다.
k 번째 가장 작은 요소를 찾기 위해 가장 무례한 방법은 모든 요소를 정렬하는 것이지만 이것은 많은 추가 작업을 수행했습니다. 빠른 정렬 알고리즘의 일회성 정렬 아이디어를 바탕으로 배열의 첫 번째 요소를 표준으로 사용하고 왼쪽보다 작은 요소를 배치 할 수 있습니다. 오른쪽보다 크게 배치 :
- 이 표준의 왼쪽에있는 요소가 k가되면 k 번째로 작은 수를 찾습니다.
- 이 표준의 왼쪽에있는 요소의 합이 k 미만이면 오른쪽으로 계속 진행하여 가장 작은 숫자 (숫자의 k-1- 첨자)를 찾습니다.
- 이 표준의 왼쪽에있는 요소의 합이 k보다 크면 왼쪽으로 계속 진행하여 k 번째로 작은 수를 찾습니다.
알고리즘 구현
#include <iostream>
#include <algorithm>
#define N 100
using namespace std;
//一维数组容器
int a[N];
//线性选择算法寻找第k小的元素
int linearTimeSelection(int,int,int);
int main()
{
int n,k;
cout<<"输入数组大小:";
cin>>n;
if(n>N || n<1) {
cout<<"预留空间不足或数组大小非法!";
exit(0);
}
cout<<"输入数组元素:";
for(int i=0;i<n;i++) cin>>a[i];
cout<<"查找第几小的元素:";
cin>>k;
if(k > n || k < 1){
cout<<"查找位置非法!";
exit(0);
}
cout<<linearTimeSelection(0,n-1,k);
return 0;
}
/*
left 进行线性选择的首位下标
right 进行线性选择的末尾下标
k 寻找第k位小的元素
*/
int linearTimeSelection(int left,int right,int k){
if(left >= right) return a[left];
int point = a[left];
int i = left,
j = right+1;
while(1){
do{
i++;}while(a[i] < point);
do{
j--;}while(a[j] > point);
if(i>=j) break;
swap(a[i],a[j]);
}
if(j-left+1 == k) return point;
a[left] = a[j];
a[j] = point;
if(j-left+1 < k) return linearTimeSelection(j+1,right,k-(j+1-left)); //向右找
return linearTimeSelection(left,j-1,k); //向左找
}
예 2
문제 설명
한 석유 회사는 동쪽에서 서쪽으로 주요 송유관을 건설 할 계획입니다. 파이프 라인은 n 개의 유정이있는 유전을 통과합니다. 각 유정에는 최단 경로 (또는 남쪽 또는 북쪽)를 따라 주 파이프 라인에 연결된 송유관이 있어야합니다.
n 개의 유정의 위치, 즉 x 좌표 (동서)와 y 좌표 (북-남)가 주어지면 프로그램은 각 유정에서 주 파이프 라인까지의 최소 송유관 길이의 합계를 계산합니다.
입력
첫번째 라인의 정수, n은 유정의 개수 (1≤n≤10 000)에 지시한다
, 다음 N 라인은 유정의 위치이다를, 각 라인은 두 정수 x와 y 포함 (-10 000≤x을 y≤10 000) 각 유정에서 주 파이프 라인까지 송유관의 총 최소 길이를
출력
합니다.
입력 예
5
1 2
2 2
1 3
3 -2
3/3
출력 예
6
샘플 다이어그램
문제 분석
- 주요 송유관의 위치를 결정하는 방법은 무엇입니까?
위의 입력 샘플에 그린 분석 다이어그램에서 메인 파이프는 y 좌표에 의해서만 결정되고 메인 파이프는 y 값의 범위 (즉, 입력 y 좌표의 최대 값과 최소값)에 존재 함을 분명히 알 수 있습니다. 사이), 유정과 주 파이프 라인 사이의 거리와 최소값을 구해야 하므로 유정 위치의 y 값의 중앙값 을 찾으십시오 . - 최소 거리 합계를 계산하는 방법은 무엇입니까?
주관로의 위치를 찾은 후 각 유정에 대한 주관로까지의 거리를 계산하여 합산합니다. - 중앙값 계산에 관하여
1. 직접 정렬, n / 2 첨자가있는 요소 찾기
2. 선형 시간 선택 알고리즘을 사용하여 n / 2 번째 가장 작은 요소 선택 (이 방법을 사용함)
알고리즘 구현
#include <iostream>
#include <algorithm>
#define N 10000
using namespace std;
//存储油井的y值
int a[N];
//线性时间选择算法
int linearTimeSelection(int,int,int);
int main()
{
int n,temp;
cout<<"请输入油井的数量:";
cin>>n;
cout<<"请输入油井坐标:";
for(int i=0;i<n;i++)
cin>>temp>>a[i];
//主管道位置
int mid = linearTimeSelection(0,n-1,n/2);
int sum = 0;
for(int i=0;i<n;i++){
sum += abs(a[i]-mid);
}
cout<<sum<<endl;
return 0;
}
int linearTimeSelection(int left,int right,int k){
if(left >= right) return a[left];
int i = left,
j = right+1;
int point = a[left];
while(1){
do{
i++;}while(a[i]<point);
do{
j--;}while(a[j]>point);
if(i>=j) break;
swap(a[i],a[j]);
}
if(j-left+1 == k) return point;
a[left] = a[j];
a[j] = point;
if(j-left+1 < k) return linearTimeSelection(j+1,right,k-(j-left+1));
return linearTimeSelection(left,j-1,k);
}
이 블로그의 다른 기사에서 추천
알고리즘 설계 및 분석을위한 전략 연습 분할 및 정복 (2 부)
알고리즘 설계 및 분석을위한 전략 연습 분할 및 정복 (on)