【复习】递归与分治

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//二分查找最值
int findmax(int a[], int l, int r) {
	int maxl = a[l], maxr = a[r];
	if (l < r) {
		int mid = (l + r) / 2;
		maxl = findmax(a, l, mid);
		maxr = findmax(a, mid + 1, r);
		return (maxl >= maxr) ? maxl : maxr;
	}
	else return (maxl >= maxr) ? maxl : maxr;
}

typedef struct node {
	int data;
	struct node* next;
}node;
node* com(node* l1, node* l2) {
	if (!l1 && l2) {//最后一个l1都比l2小,则最后一个l1指向l2
		return l2;
	}
	if (l1 && !l2) {
		return l1;
	}
	if (!l1 && !l2)
		return NULL;
	node* p = (node*)malloc(sizeof(node));
	if (l1->data <= l2->data) {

		p->next = com(l1->next, l2);
	}
	else {

		p->next = com(l1->next, l2);
	}

	return p;//p充当两个作用,一个是用于返回给上一个结果,另一个是寻找下一个结果
}

//判断漂亮数组
bool beauty(int a[], int n) {
	int i, j, k;
	for (i = 0; i <= n - 2; i++) {
		for (j = i + 2; j < n; j++) {
			for (k = i + 1; k < j; k++)
				if ((a[i] + a[j]) / 2 == k)
					return false;
		}
	}
	return true;
}
int swap(int a[], int x, int y) {

}
void perm(int a[], int p, int q, int n) {
	if (p == q) {
		if (beauty(a, n)) {
			for (int i = 0; i < n; i++)
				printf("%d", a[i]);
		}
	}
	else {
		for (int i = p; i < n; i++) {
			swap(a, p, i);
			perm(a, p + 1, q, n);
			swap(a, p, i);
		}
	}


}


//划分为k个相等数组
int visited[17];//如果某个元素已经被访问,我们就用visited数组来把该元素标识为1
int end;//end与k相等,所以当子集的个数与end相等时,就说明符合条件,返回true
int aver;//等于所有元素和除于k
bool dfs(int* nums, int numsSize, int nowLen, int nowGet, int pos){//pos当前搜索位置,nowGet当前子集个数,nowlen当前子集和,
	int i;
	if (pos >= numsSize)//当当前搜索到的位置超出数组的边界时,很明显不符合条件
		return false;
	if (nowGet == end)//当当前符合条件的子集个数等于k时,就说明符合条件,返回true
		return true;
	for (i = pos; i < numsSize; i++){
		if (visited[i] != 1) {//已经访问过的元素跳过
			if (nowLen + nums[i] == aver){//当前获取子集的元素和等于平均值时,说明符合条件
				visited[i] = 1;//元素的已访问标识
				/*最后一个参数的含义为,我们从第一个元素开始查找,如果第一个元素符合条件,我们就从第二个元素开始找,以此类推,当我们第n个子集符合条件时,我们就从第n + 1个元素开始查找,nowGet + 1个元素所对应的下标为nowGet*/
				if (dfs(nums, numsSize, 0, nowGet + 1/*子集个数增加1*/, nowGet))//判断后面的元素是否符合条件
					return true;
				visited[i] = 0;//不符合条件的话,恢复为0,注意,if(递归) return的效果是,只有if不执行,才执行下面语句。
			}
			else if (nowLen + nums[i] < aver){
				//跟上面大同小异,不再详解
				visited[i] = 1;
				if (dfs(nums, numsSize, nowLen + nums[i], nowGet, i + 1))
					return true;
				visited[i] = 0;
				for (; i + 1 < numsSize && nums[i] == nums[i + 1]; i++);//当该元素不符合条件,后面的与他一样的元素肯定不符合,可以跳过
			}
		}
	}
	return false;
}
bool canPartitionKSubsets(int* nums, int numsSize, int k)
{
	memset(visited, 0, sizeof(visited));
	end = k;
	aver = 0;
	for (int i = 0; i < numsSize; i++)
		aver += nums[i];
	aver /= k;
	if (dfs(nums, numsSize, 0, 0, 0))
		return true;
	else
		return false;
}

///2020真题 7 子弹射击
//子弹和目标序列
//20201126总结:首先该递归是2的n次方模型,因此采用二叉树遍历方法递归,每次到根节点产生一个最大值,取最大的得分
/*穷举法三要素:
1 确定是几叉树,即每次递归有几种可选情况
2 确定递归效果:遍历、加总分、减路程……
3 确定递归出口:什么时候遍历到叶子结点,有时在叶子结点还会产生很多可行解,需要进行筛选,如最值,范围值。
*/
#define n 4;
int score = 0,max=0;
int shoot(int a[],int b[],int i,int j) {
	if (i == 3) {
		/*return;*/
		//不能直接return
		if (score > max)
			max = score;
		return;
	}
	else {
		/*if (a[i] == b[j])
			score++;
		shoot(a, b, i + 1, j + 1);
		shoot(a, b, i + 1, j);*/
		//错因:当相等时,一定执行i+1,j+1;
		if (a[i] == b[j]) {
			shoot(a, b, i + 1, j + 1);
			score++;
		}
		shoot(a, b, i+1, j);
		shoot(a, b, i + 1, j + 1);
		return;
	}
}
void scoree() {
	int a[4] = {1,2,3,4};
	int b[4] = { 1,2,3,4 };
	shoot(a,b, 0, 0);
}

//棋盘覆盖
int title = 0;
#define size 10
int board[size][size];
void chessboard(int tr,int tc,int dr,int dc,int s) {//dr,dc是特殊棋盘,tr,tc是棋盘左上角行和列
	if (s == 1)
		return;
	int t = title++;
	int s = size / 2;

	//左上棋盘
	if(dr<tr+s&&dc<tc+s){
		chessboard(tr,tc, dr, dc, s);
	}
	else {
		board[tr+s-1][tr+s-1] = t;
		chessboard(tr, tc, tr + s - 1, tr + s - 1, s);
	}
	//右上
	if (dr < tr + s && dc >= tc + s) {
		chessboard(tr, tc, dr, dc, s);
	}
	else {
		board[tr + s-1][tc + s]=t;
		chessboard(tr, tc+s, tr + s - 1, tc - s,s);
	}
	//左下
	if (dr >= tr + s && dc < tc + s) {
		chessboard(tr, tc, dr, dc, s);
	}
	else {
		board[tr + s][tc + s - 1];
		chessboard(tr+s, tc, tr + s, tc + s - 1,s);
	}
	//右下
	if (dr >= tr + s && dc >= tc + s) {
		chessboard(tr, tc, dr, dc, s);
	}
	else {
		board[tr + s][tc + s];
		chessboard(tr+s, tc+s, tr + s, tc + s, s);
	}


}

/*
跳房子游戏:n个石子位置固定,移动固定石子,使得剩余石子之间的最小距离最大化,求该最小距离。
1 首先简化模型:给定一个距离d,移动哪些石子,使得最小距离>d。
方法:若某个石子到d0的距离<d,则一定移除,因为设置d0为基准,移除到该点距离小于d的石子,保留最近一个
距离>d的石子,并将它作为新的基准,继续移除由此基准出发,到剩余石子距离<d的石子,循环该过程,记录移除
的石子数量。
2 然后升级模型:将固定距离由大到小循环,方法为二分法。找到每个d下,需要移除的石子数量,根据数量,判断
该d是否满足条件。判断依据:若移除数量>规定移除数量,则说明若按照规定移除数量进行移除,区间太小,即d过小。
则根据二分法原则,min增大。反之,max减小。直到min>max,输出d,即为最大区间。
*/
int a[];
int m = 2;
int find(int x) {
	int now = 0, left = 0;//now基准
	for (int i = 1; i <= n + 1; i++) {
		if (a[i] - a[now] > x)
			left++; now = i;
	}
	if (left < n - m)//如果移除过多,即k设置小了
		return 1;
	else return 0;
}
int jumpstone(int l) {
	int maxl = l, minl = 1, k, ans;

	while (minl < maxl) {
		k = (maxl + minl) / 2;
		if (find(k)) {//k小了
			ans = k; minl = k + 1;
		}
		else maxl = k - 1;
	}
	return k;
}
//二分法判断是否有满足带入方程计算后=b的数组a的值
void cal() {
	int n,a[100];
	scanf_s("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf_s("%d", &a[i]);
	}
	int q,b[100],p=0;
	scanf("%d", &q);
	for (int i = 0; i < q; i++) {
		scanf_s("%d", &b[i]);
	}
	while (p<q) {
		int low = 0,high = n - 1,f=0;
		while (low <= high) {
			int mid = (low + high) / 2;
			int x = 6 * pow(a[mid], 2) + 4 * pow(a[mid], 3) + 5 * pow(a[mid], 6);
			if (b[p] == x) {
				printf("YES");
				f = 1;
			}
			else if (x > b[p])
				high = mid - 1;
			else low = mid + 1;
		}
		if (!f)
			printf("No");
		p++;
	}

}

int main() {
	int a[] = { 5,7,2,9,100,-5 };
	int max = findmax(a, 0, 5);
	printf("%d", max);
	system("pause");
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值