算法笔记 分治:循环赛日程 棋盘覆盖 选择问题 输油管问题 整数因子分解

一.循环赛日程

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#define MAX 100
using namespace std;

int a[MAX][MAX];

// 拷贝方阵
// 从左上角顶点为(from_x, from_y)复制到左上角顶点为(to_x,to_y),行列式都为r
void Copy(int tox, int toy, int fromx, int fromy, int r)
{
	for (int i=0; i<r; i++)
		for (int j=0; j<r; j++)  
			a[tox+i][toy+j] = a[fromx+i][fromy+j];
}

// 人数是2^k
void Table(int k)
{	
	int i, r;
	int n = 1 << k;	
	//构造正方形表格的第一行数据
	for (i=0; i<n; i++)
		a[0][i] = i + 1;
	
	// 分治,从第一行开始向下一行复制
    // 然后从已经产生的列表向下继续复制(原来又两行,就向下复制两行)
	for (r=1; r<n; r<<=1)
		for (i=0; i<n; i+=2*r)
		{ 
			Copy(r, r + i, 0, i, r);		//①
			Copy(r, i, 0, r + i, r);		//②
		}
}

int main() 
{
	Table(3);
	for(int i = 0;i < 8;i++){
		for(int j = 0;j < 8;j++)
			cout << a[i][j] << " ";
		cout<<endl;
	}
}           

在这里插入图片描述
在这里插入图片描述

二.棋盘覆盖

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#define MAX 1025
using namespace std;

int board[MAX][MAX];
static int tile = 1;            // 骨牌编号 

// (tr,tc)是棋盘中左上角的方格坐标
//(dr,dc)是特殊方格坐标
// size是棋盘的行数或列数 
void ChessBoard(int tr,int tc,int dr, int dc, int size)
{
	if(size == 1) return;       // 递归出口,如果边长是1的话,那他就是特殊方格
	
	int t = tile++;				// 骨牌编号 
	int s = size/2;				// 划分小的棋盘 
	
	// 覆盖左上角子棋盘
	if(dr < tr + s && dc < tc + s)		// 特殊方格在这个棋盘中
		ChessBoard(tr,tc,dr,dc,s);		// 去划分更小的棋盘 
	else{
		// 没有特殊方格,用一个L骨牌中的一小格覆盖右下角,将这个小格当成特殊方格 
		// 到时候这些小格会拼成一个完整的L形骨牌
		board[tr+s-1][tc+s-1] = t;
		// 覆盖其他方格
		ChessBoard(tr,tc,tr+s-1,tc+s-1,s); 
	} 	 
	
	// 覆盖右上角子棋盘
	if(dr < tr + s && dc >= tc + s)		// 特殊方格在这个棋盘中
		ChessBoard(tr,tc+s,dr,dc,s);		// 去划分更小的棋盘 
	else{
		// 没有特殊方格,用一个L骨牌中的一小格覆盖左下角,将这个小格当成特殊方格 
		// 到时候这些小格会拼成一个完整的L形骨牌
		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+s,tc,dr,dc,s);		// 去划分更小的棋盘 
	else{
		// 没有特殊方格,用一个L骨牌中的一小格覆盖右上角,将这个小格当成特殊方格 
		// 到时候这些小格会拼成一个完整的L形骨牌
		board[tr+s][tc+s-1] = t;
		// 覆盖其他方格
		ChessBoard(tr+s,tc,tr+s,tc+s-1,s); 
	} 	
	
	// 覆盖右下角子棋盘
	if(dr >= tr + s && dc >= tc + s)		// 特殊方格在这个棋盘中
		ChessBoard(tr+s,tc+s,dr,dc,s);		// 去划分更小的棋盘 
	else{
		// 没有特殊方格,用一个L骨牌中的一小格覆盖左上角,将这个小格当成特殊方格 
		// 到时候这些小格会拼成一个完整的L形骨牌
		board[tr+s][tc+s] = t;
		// 覆盖其他方格
		ChessBoard(tr+s,tc+s,tr+s,tc+s,s); 
	} 	   	 
}

int main() 
{
	int k;
	int dr, dc;
	
	cout << "输入边长k,即size = 2^k" << endl; 
	cin >> k;
	int size = pow(2, k);
	
	cout << "特殊方格坐标" << endl; 	
	cin >> dr >> dc;	
	
	ChessBoard(0,0,dr,dc,size);
	
	for(int i = 0;i < size;i++){
		for(int j = 0;j <size;j++)
			cout << board[i][j] << " ";
		cout << endl;
	}
}           

在这里插入图片描述

三.选择问题

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#define NUM 1001
using namespace std;

int a[NUM];

// 选择第k小的元素
int select(int *a, int left, int right, int k)
{
	// 找到第k小的元素
	if(left >= right)  return a[left];
	int i = left;
	int j = right + 1;
	
	// 将左边的元素化为分界点
	int pivot = a[left];
	
	// 把左侧>=pivot的元素和右侧<=pivot的原色交换
	while(true)
	{
		// 在左侧寻找>=pivot的元素
		do {
			i += 1;	
		} while(a[i] < pivot);
		
		// 在右侧寻找<=pivot的元素 
		do {
			j -= 1;
		} while(a[j] > pivot);
		
		//cout << i << " " << j << endl;
		
		if(i >= j)  break;
		swap(a[i], a[j]);
	} 
	
	// 快排中 num_left = j - left
	if(j - left + 1 == k)  return pivot;
	a[left] = a[j];     // 交换pivot和a[j],走到这一步,p后面的数据已经排好序了
						// i和j找的是离p最近的大的数字和小的数字 
	a[j] = pivot;

	//cout << "a[left]" << " " << a[left] << endl;
	//cout << "a[j]" << " " << a[j] << endl;
	//cout << "pivot" << " " << pivot << endl;
	//cout << endl;
	
	if(j - left + 1 < k)
		return select(a, j + 1,right, k - j + left - 1);   // 往右边找
	else
		return select(a, left, j - 1, k); 					// 往左边找 
 } 

int main() 
{
	int n , k;
	cout << "输入数组个数和查找的元素大小的次数" << endl;
	cin >> n >> k;
	
	cout << "输入元素" << endl; 
	for(int i = 0;i < n;i++)
	{
		cin >> a[i];
	 } 
	
	cout << select(a, 0, n-1, k); 
	
}           

在这里插入图片描述

四.输油管问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#define NUM 1001
using namespace std;

int a[NUM];

// 选择第k小的元素
int select(int left, int right, int k)
{
	// 找到第k小的元素
	if(left >= right)  return a[left];
	int i = left;
	int j = right + 1;
	
	// 将左边的元素化为分界点
	int pivot = a[left];
	
	// 把左侧>=pivot的元素和右侧<=pivot的原色交换
	while(true)
	{
		// 在左侧寻找>=pivot的元素
		do {
			i += 1;	
		} while(a[i] < pivot);
		
		// 在右侧寻找<=pivot的元素 
		do {
			j -= 1;
		} while(a[j] > pivot);
		
		//cout << i << " " << j << endl;
		
		if(i >= j)  break;
		swap(a[i], a[j]);
	} 
	
	// 快排中 num_left = j - left
	if(j - left + 1 == k)  return pivot;
	a[left] = a[j];     // 交换pivot和a[j],走到这一步,p后面的数据已经排好序了
						// i和j找的是离p最近的大的数字和小的数字 
	a[j] = pivot;

	//cout << "a[left]" << " " << a[left] << endl;
	//cout << "a[j]" << " " << a[j] << endl;
	//cout << "pivot" << " " << pivot << endl;
	//cout << endl;
	
	if(j - left + 1 < k)
		return select(j + 1,right, k - j + left - 1);   // 往右边找
	else
		return select(left, j - 1, k); 					// 往左边找 
 } 

int main() 
{
	int n;    	// 油井数量 
	int x;		//	x坐标,无用 
	
	//  a[]是y坐标
	cin >> n;
	for(int k = 0;k < n;k++)
	{
		cin >> x >>a[k];
	 } 
	 
	 // 快排找中位数 
	 int y = select(0, n-1, n/2);
	 
	 int min = 0;
	 for(int i = 0;i < n;i++){
	 	min += (int)fabs(a[i] - y);
	 } 
	 
	 cout << min << endl;
}           

五.整数因子分解

在这里插入图片描述

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#define NUM 1001
using namespace std;

int total;
void solve(int n){
	if(n == 1)  total++; // 获得一个分解
	else for(int i = 2;i <= n;i++)
		if(n % i == 0) solve(n/i);     // i是n的一个因数 
}

int main() 
{
	int n;
	cin >> n;
	solve(n);
	cout << total; 
}           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值