算法笔记2——递归分治

递归的概念:

直接或间接地调用自己的算法称为递归算法。

分治的基本思想

分治的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各个子问题的解合并得到原问题的解

递归分治的四个特性:

1、问题缩小到一定程度可以直接求解
2、(最优子结构性)原问题可分解为多个规模较小的相同子问题
3、子问题的解合并成为原问题的解
4、子问题相互独立

典型问题

1、合并排序

public class MergeSort {

    public static void sort(int[] nums, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            // 左边
            sort(nums, low, mid);
            // 右边
            sort(nums, mid + 1, high);
            // 左右归并
            merge(nums, low, mid, high);

        }
    }

    public static void merge(int[] nums, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指针
        int j = mid + 1;// 右指针
        int k = 0;

        // 把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];

            } else {
                temp[k++] = nums[j++];

            }

        }
        // 把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = nums[i++];

        }

        // 把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = nums[j++];

        }

        // 把新数组中的数覆盖nums数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }

    }
    public static void main(String[]args)
    {
    	int arr[]={1,2,7,4,6,5,3};
    	MergeSort mergeSort=new MergeSort();
    	mergeSort.sort(arr, 0, 6);
    	for(int i=0;i<=6;i++)
    	{
    		System.out.println(arr[i]);
    	}
    }

}

2、棋盘覆盖

具体的题目是:
有一个 的方格棋盘,恰有一个方格是黑色的,其它为白色。你的任务是用包含3个方格的L型牌覆盖所有白色方格。黑方格不能被覆盖,且任意一个白色方格不能同时被两个或者多个L型牌覆盖。如图为L型牌的4种旋转方式。
在这里插入图片描述
在这里插入图片描述
核心思想:
将棋盘划分为四个小部分,在交点处放置一个L形牌。这样形成四个相同的子问题。按照此思想进行递归,直到棋盘被划分到2*2.

3、快速排序

	public class sort {
	public void quickSort(int[] arr, int low, int high) {
		if (low < high) {
			int index = getIndex(arr, low, high);
			//以排好序的元素为界,将原数组分为两部分,递归
			quickSort(arr, 0, index - 1);
			quickSort(arr, index + 1, high);
		}

	}

	public int getIndex(int[] arr, int low, int high) {
		int tmp=arr[low];
		int i=low;
		int j=high;
		int t;
		while (true) {
			// 当队尾的元素大于等于基准数据时,向前挪动high指针
			while(arr[j] >= tmp && i < j)
	    		j--;
	    	while(arr[i] <= tmp && i < j)//再找右边的
	    		i++;  
	    	
	    	if(i < j)//交换两个数在数组中的位置
	    	{
	    		t = arr[i];
	    		arr[i] = arr[j];
	    		arr[j] = t;
	    	}
	    	else
	    		break;

		}
		arr[low] = arr[i];
	    arr[i] = tmp;
		return i;  
	}
	
	
	public static void main (String[]args)
	{
		int a[]={4,5,7,1,3,2,6};
		sort test=new sort();
		test.quickSort(a,0,6);
		for(int i=0;i<=6;i++)
		{
			System.out.println(a[i]);
		}
	}

}

4、循环赛日程表

设有n=2^k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:

(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能参赛一次;
(3)循环赛在n-1天内结束。

请按此要求将比赛日程表设计成有n行和n-1列的一个表。在表中的第i行,第j列处填入第i个选手在第j天所遇到的选手。其中1≤i≤n,1≤j≤n-1。8个选手的比赛日程表如下图:
在这里插入图片描述

#define _CRT_SECURE_NO_DEPRECATE;
#define _CRT_SECURE_NO_WARNINGS;
#include<stdio.h>
#define N 100
int a[N][N];

void Scheduled(int i, int size)
{
	int x, y;
	if (size == 2)
	{
		a[i][1] = i;
		a[i + 1][1] = i + 1;
	}
	else {
		Scheduled(i, size / 2);
		Scheduled(i + size / 2, size / 2);
	}

	for (x = i;x<i + size / 2;x++)
		for (y = size / 2 + 1;y <= size;y++) {
			a[x][y] = a[x + size / 2][y - size / 2];
													
		}
	for (x = i + size / 2;x<i + size;x++)
		for (y = size / 2 + 1;y <= size;y++) {
			a[x][y] = a[x - size / 2][y - size / 2];
			
		}
}

void Print(int n) {
	int p, q;
	FILE *fp;
	fp = fopen("D:\\222017321062109_循环赛.txt", "wb");

	for (p = 1;p <= n;p++) {
		for (q = 1;q <= n;q++) {
			printf("%d\t", a[p][q]);
			fprintf(fp, "%d\t", a[p][q]);
		}
		printf("\n");
		fprintf(fp, "\r\n");
	}
	fclose(fp);
}


int main() {
	int n;
	printf("请输入n的值(请确保N为2的K次方,K>=0):\n");
	scanf_s("%d", &n);
	Scheduled(1, n);
	Print(n);
	return 0;
}

发布了23 篇原创文章 · 获赞 2 · 访问量 490

猜你喜欢

转载自blog.csdn.net/weixin_42385782/article/details/103264241