分治算法

本文通过四个实例,包括洛谷P2249找数、OJ1326取余运算、OJ1325循环比赛日程表和OJ1327黑白棋子的移动,详细介绍了分治算法的应用和解题思路。针对每个问题,不仅提供了代码实现,还进行了关键分析,如数值分解、对称性利用等,帮助理解分治策略在不同场景下的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例1 洛谷P2249找数

【代码1 左端点】

#include <bits/stdc++.h>
using namespace std;
int n,m,a[100005];
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	while(m--){
		int k;
		cin>>k;
		int l,r;
		l=1,r=n;
		while(l<r){
			int mid=(l+r)/2;
			if(a[mid]>=k) r=mid;
			else l=mid+1;
		}
		if(a[r]==k) cout<<r<<" ";
		else cout<<-1<<" "; //没有找到的情况
	}
	return 0;
}

【代码2 右端点】

#include <bits/stdc++.h>
using namespace std;
int n,m,a[100005];
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	while(m--){
		int k;
		cin>>k;
		int l,r;
		l=1,r=n;
		while(l<r){
			int mid=(l+r+1)/2;//此处必须加1,使l=r+1时能够取到mid的值,避免出现死循环
			if(a[mid]<=k) l=mid;
			else r=mid-1;
		}
		if(a[r]==k) cout<<r<<" ";
		else cout<<-1<<" ";
	}
}

例2 OJ1326 取余运算mod

【分析】

1. b,p,k×k为长整型数,应该进行分解

(原理:(a*b)%k=(a%k)*(b%k)%k )

2.注意输出格式

【代码】

#include <bits/stdc++.h>
using namespace std;
long long f(long long b,long long p,long long k){
	long long temp=1;//长整型,记得开long long,temp赋初值为1
	while(p>0){//指数为正时
		if(p%2==1) temp=temp*b%k;//指数为奇数时,
		b=b*b%k;
		p/=2;//二分
 	}
 	return temp;
}
int main(){
	long long b,p,k;
	cin>>b>>p>>k;
	printf("%d^%d mod %d=%d",b,p,k,f(b,p,k));
	return 0;
}

例3 OJ1325 循环比赛日程表

 【分析】

在输出样例中寻找规律,发现方阵的对称性,即左上角等于右下角,右上角等于左下角,并找到四个部分之间的规律

【代码】

#include <bits/stdc++.h>
#define N 1025
using namespace std;
int a[N][N];
int main(){
	a[1][1]=1;
	int m;
	cin>>m;
	int k=1,h=1;//h表示2的k-1次方 
	while(k<=m){
		for(int i=1;i<=h;i++){
			for(int j=1;j<=h;j++){
				a[i][j+h]=a[i][j]+h;//构造右上角的数据 
			}
		}
		for(int i=1;i<=h;i++){
			for(int j=1;j<=h;j++){
				a[i+h][j]=a[i][j+h];//左下角的数据 
				a[i+h][j+h]=a[i][j];//右下角的数据 
			}
		}
		k++;//递增 
		h*=2;
	}
	for(int i=1;i<=h;i++){
		for(int j=1;j<=h;j++){
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

例4 OJ1327 黑白棋子的移动(洛谷P1259)

【分析】

1.

当n=4的时候, 把4开始的2个移动到空位置 ,
把8开始的2个移动到空位置 ,
把2开始的2个移动到空位置 ,
把7开始的2个移动到空位置 ,
把1开始的2个移动到空位置。

2.n>4时 将n移到2n+1 再由2n-1移到n-1 

【代码】 

#include <iostream>
#include <cstdio>
using namespace std;
int n,m;
char c[5000],kg,s=0;//kg为空格,s为步骤 
void print(){
	printf("step%2d:",s++);
	for(int i=1;i<=2*n+2;i++){
		cout<<c[i];
	}//定义输出函数 
	cout<<endl;
}
void move(int k){
	for(int i=0;i<=1;i++){
		swap(c[i+kg],c[i+k]);
	}
	kg=k;
	print();
}//定义移动函数 
void dt(int n){
	if(n==4){
		move(4);move(8);move(2);move(7);move(1);
	}//n=4时需要特判 根据输出样例发现规律 
	else{
		move(n);move(2*n-1);//其余情况为普遍规律
		dt(n-1);
	}
}//递归调用 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		c[i]='o';
		c[i+n]='*';
	}
	c[2*n+1]=c[2*n+2]='-';//设置黑白棋子和空格 
	print();
	kg=2*n+1;
	dt(n);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值