分治

分治算法

分治算法即为把一个规模为n的问题,分为几个规模为k的子问题,并且最好使子问题规模大小相近且较小,这些子问题相互独立且与原问题性质相同,这可以使解决问题更具条理性。
分解,将要解决的问题划分成若干规模较小的同类问题;(可以递归的分解)
求解,当子问题划分得足够小时,用较简单的方法解决;
合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。(也可以使用递归……)

经典例题

寻找伪币

题目描述

给你一个装有16枚硬币的袋子。16枚硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。你的任务是找出这枚伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,比如天平。利用这台仪器,可以知道两组硬币的重量是否相同。(注意:必须用分治做!)

输入格式

一行,包含16个正整数,用空格隔开,每个正整数不大于10, 其中15个数相同,1个数小于其它15个数

输出格式

一行,两个数,用空格隔开 第一个数是伪币的输入编号,第二个数是伪币的重量

样例

样例输入

2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2

样例输出

4 1

代码

与二分思想相近,首先将十六枚伪币分为八个一组,四个一组,二个一组,通过不断减小问题规模,将其简化值两个数比大小。
当然也可以暴枚,只不过……mjl的愤怒……
#include<bits/stdc++.h>
using namespace std;
const int M_AX=1e5+7;
long long a[M_AX];
int main(){
	for(int i=0;i<16;i++)std::cin>>a[i];
	int left=-1,right=16,mid;
	if(a[0]==a[1])mid=a[0];
	else mid=a[3];
	while(left!=right){
		left++,right--;
		if(a[left]==a[right])continue;
		if(a[left]==mid)std::cout<<right+1<<" "<<a[right]<<endl;
		else std::cout<<left+1<<" "<<a[left]<<endl;
		return 0;
	}
	return 0;
} 

寻找最值

题目描述

输入一个序列,寻找最大值和最小值并输出(注意:用分治来做)

输入格式

两行 第一行1个数n,表示序列的个数1≤n≤1000000 第二行,n个int范围的数,用空格隔开

输出格式

一行,两个数 最大值和最小值,用空格隔开

样例

样例输入

5
6 8 4 1 9

样例输出

9 1

代码

和上一道题一样,减半再减半,于是乎……就A了,如果用选择结构,也可以A,数据太垃圾,1000ms超时的才是大佬。
为防止被制裁,我选择隐瞒一下我非分治的做法……
#include<bits/stdc++.h>
using namespace std;
const int M_AX=300005;
int n,a[M_AX];
int main(){
	std::cin>>n;
	for(int i=1;i<=n;i++)std::cin>>a[i];
	int _min=1e9,_max=-1e9;
	for(int i=1;i<=n;i++){
		if(a[i]>_max)_max=a[i];
		if(a[i]<_min)_min=a[i];
	}
	std::cout<<_max<<" "<<_min;
	return 0;
} 

快速幂

样例

样例输入

2 10

样例输出

思路很简单,别忘记%12345:
当b%2==0 a的b/2的2次方
否则 为a的b/2的2次方乘以a

#include<bits/stdc++.h>
using namespace std;
long long a,b,c=12345,d;
long long Remainder_operation(int b){
	if(b==0)return 1;
	long long sum=Remainder_operation(b/2)%c;
	sum=(sum*sum)%c;
	if(b%2==1)sum=(sum*(a%c))%c;
	return sum;
}
int main(){
	scanf("%lld %lld",&a,&b);
	a%=c;
	printf("%lld",Remainder_operation(b));
	return 0;
} 
posted @ 2021-04-01 13:39  黄逸飞重庆八中  阅读(76)  评论(0编辑  收藏  举报