算法里面的“分治”,是把一个大问题分成小问题,各个击破,“分而治之(Divide and Conquer)”。而分治算法的具体操作,是把原问题分成 k 个较小规模的子问题,对这 k 个子问题分别求解。如果子问题不够小,那么把每个子问题再划分为规模更小的子问题。这样一直分解下去,直到问题足够小,很容易求出这些小问题的解为止。
能用分治法的题目,需要符合两个特征:
- 平衡子问题:子问题的规模大致相同。能把问题划分成大小差不多相等的 k 个子问题,一般是 k=2,即分成两个规模相等的子问题。编码的时候,每次分成两部分,然后继续分成两部分 ⋯ 该步骤和二分法很像。 当然,二分法也是分治法,只是二分法的应用场合非常简单。
- 独立子问题:子问题之间相互独立。这是区别于动态规划算法的根本特征,在动态规划算法中,子问题是相互联系的,而不是相互独立的。
分治法的思想,几乎就是递归的过程,用递归程序实现分治法是很自然的。用分治法建立模型时,解题步骤分为三步:
- 分解(Divide):把问题分解成独立的子问题;
- 解决(Conquer):递归解决子问题;
- 合并(Combine):把子问题的结果合并成原问题的解。
样例输入
3 2
样例输出
#2: A->B
7
import java.util.Scanner;
public class Main {
private static int ans = 0;
private static int M;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
M = scanner.nextInt();
fun('A', 'B', 'C', N);
System.out.println(ans);
}
public static void fun(char A, char B, char C, int n) {
if (n == 1) {
ans++;
if (M == ans) System.out.println("#" + M + ":" + A + "->" + C);
return;
} else {
fun(A, C, B, n - 1);
ans++;
if (M == ans) System.out.println("#" + M + ":" + A + "->" + C);
fun(B, A, C, n - 1);
}
}
}
归并排序
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
typedef long long ll;
int a[N], b[N];
ll cnt;
void Merge(ll l, ll mid, ll r){
ll i=l, j = mid+1, t=0;
while(i <= mid && j <= r){
if(a[i] > a[j]){
b[t++] = a[j++];
cnt += mid-i+1; //记录逆序对数量
}
else b[t++]=a[i++];
}
//一个子序列中的数都处理完了,另一个还没有,把剩下的直接复制过来:
while(i <= mid) b[t++]=a[i++];
while(j <= r) b[t++]=a[j++];
for(i=0; i<t; i++) a[l+i] = b[i]; //把排好序的b[]复制回a[]
}
void Mergesort(ll l, ll r){
if(l<r){
ll mid = (l+r)/2; //平分成两个子序列
Mergesort(l, mid);
Mergesort(mid+1, r);
Merge(l, mid, r); //合并
}
}
int main(){
int n,k;
cin >>n;
cnt = 0;
for(int i=0;i<n;i++) scanf("%d", &a[i]);
Mergesort(0,n-1); //归并排序
cout <<cnt;
return 0;
}
快速排序
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextInt();
quick_sort(a, 0, n - 1);
for (int i = 0; i < n; i++) System.out.print(a[i] + " ");
System.out.print("\n");
for (int i = n - 1; i >= 0; i--) System.out.print(a[i] + " ");
System.out.print("\n");
}
public static void quick_sort(int[] a, int l, int r) {
if (l >= r) return;
int i = l, j = r, base = a[l];
while (i < j) {
while (a[j] >= base && i < j) j--;
while (a[i] <= base && i < j) i++;
swap(a, i, j);
}
swap(a, l, j);
quick_sort(a, l, j - 1);
quick_sort(a, i + 1, r);
}
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}