目录
作者的话
大底包含了算法硬性规定的作业代码,并非最优解,仅供参考并会持续更新。勿要无脑copy,对自己负责。如果代码有误或者优化建议,直接相应博客下方评论或者qq找我如果对代码有理解不了的或者疑惑可以询问我,但是请确保你已经自己思考过或者查过搜索引擎(如果我原模原样搜到了资料的话我会锤你的hh)。一些语法和库的资料查询网站受个人风格影响,部分题目解题方式可能没按照教学要求,如有必要请自己按教学要求做一遍。如果可以的话,麻烦借鉴完以后给我博客来个三连啥的,这可能对我以后找工作或者其他博客的推广什么的有些帮助,感谢
题目一棋盘覆盖问题
在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
题目有问题,应输入3 2 3,而不是8 2 3
C++版
#include <iostream>
#include<iomanip>
using namespace std;
using std::setw;
const int MAXN = 2050;
int board[MAXN][MAXN]; // 棋盘
int tile = 1; // L型骨牌编号
// 分治递归函数
void solve(int tr, int tc, int dr, int dc, int size) {
if (size == 1) return; // 当前棋盘已经覆盖完毕
int t = tile++; // 当前使用的L型骨牌编号
int s = size / 2; // 棋盘大小的一半
// 对左上角棋盘进行分治覆盖
if (dr < tr + s && dc < tc + s)
solve(tr, tc, dr, dc, s);
else {
board[tr + s - 1][tc + s - 1] = t;
solve(tr, tc, tr + s - 1, tc + s - 1, s);
}
// 对右上角棋盘进行分治覆盖
if (dr < tr + s && dc >= tc + s)
solve(tr, tc + s, dr, dc, s);
else {
board[tr + s - 1][tc + s] = t;
solve(tr, tc + s, tr + s - 1, tc + s, s);
}
// 对左下角棋盘进行分治覆盖
if (dr >= tr + s && dc < tc + s)
solve(tr + s, tc, dr, dc, s);
else {
board[tr + s][tc + s - 1] = t;
solve(tr + s, tc, tr + s, tc + s - 1, s);
}
// 对右下角棋盘进行分治覆盖
if (dr >= tr + s && dc >= tc + s)
solve(tr + s, tc + s, dr, dc, s);
else {
board[tr + s][tc + s] = t;
solve(tr + s, tc + s, tr + s, tc + s, s);
}
}
int main() {
int k, x, y;
cin >> k >> x >> y; // 特殊方格的坐标
// 初始化棋盘
int size = 1 << k; // 棋盘大小为2^k
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
board[i][j] = -1;
// 设置特殊方格
board[x][y] = 0;
// 分治递归覆盖棋盘
solve(0, 0, x, y, size);
// 输出结果
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
cout<<setw(3)<< borad[i][j] ;
}
cout << endl;
}
return 0;
}
python版
MAXN = 2050
board = [[-1] * MAXN for _ in range(MAXN)] # 棋盘
tile = 1 # L型骨牌编号
# 分治递归函数
def solve(tr, tc, dr, dc, size):
global tile
if size == 1:
return # 当前棋盘已经覆盖完毕
t = tile # 当前使用的L型骨牌编号
tile += 1
s = size // 2 # 棋盘大小的一半
# 对左上角棋盘进行分治覆盖
if dr < tr + s and dc < tc + s:
solve(tr, tc, dr, dc, s)
else:
board[tr + s - 1][tc + s - 1] = t
solve(tr, tc, tr + s - 1, tc + s - 1, s)
# 对右上角棋盘进行分治覆盖
if dr < tr + s and dc >= tc + s:
solve(tr, tc + s, dr, dc, s)
else:
board[tr + s - 1][tc + s] = t
solve(tr, tc + s, tr + s - 1, tc + s, s)
# 对左下角棋盘进行分治覆盖
if dr >= tr + s and dc < tc + s:
solve(tr + s, tc, dr, dc, s)
else:
board[tr + s][tc + s - 1] = t
solve(tr + s, tc, tr + s, tc + s - 1, s)
# 对右下角棋盘进行分治覆盖
if dr >= tr + s and dc >= tc + s:
solve(tr + s, tc + s, dr, dc, s)
else:
board[tr + s][tc + s] = t
solve(tr + s, tc + s, tr + s, tc + s, s)
# 主程序
k, x, y = map(int, input().split()) # 特殊方格的坐标
# 初始化棋盘
size = 1 << k # 棋盘大小为2^k
for i in range(size):
for j in range(size):
board[i][j] = -1
# 设置特殊方格
board[x][y] = 0
# 分治递归覆盖棋盘
solve(0, 0, x, y, size)
# 输出结果
for i in range(size):
for j in range(size):
print(board[i][j], end='\t')
print()
java版
import java.util.Scanner;
public class Main {
static int MAXN = 2050;
static int[][] board = new int[MAXN][MAXN]; // 棋盘
static int tile = 1; // L型骨牌编号
// 分治递归函数
public static void solve(int tr, int tc, int dr, int dc, int size) {
if (size == 1)
return; // 当前棋盘已经覆盖完毕
int t = tile++; // 当前使用的L型骨牌编号
int s = size / 2; // 棋盘大小的一半
// 对左上角棋盘进行分治覆盖
if (dr < tr + s && dc < tc + s)
solve(tr, tc, dr, dc, s);
else {
board[tr + s - 1][tc + s - 1] = t;
solve(tr, tc, tr + s - 1, tc + s - 1, s);
}
// 对右上角棋盘进行分治覆盖
if (dr < tr + s && dc >= tc + s)
solve(tr, tc + s, dr, dc, s);
else {
board[tr + s - 1][tc + s] = t;
solve(tr, tc + s, tr + s - 1, tc + s, s);
}
// 对左下角棋盘进行分治覆盖
if (dr >= tr + s && dc < tc + s)
solve(tr + s, tc, dr, dc, s);
else {
board[tr + s][tc + s - 1] = t;
solve(tr + s, tc, tr + s, tc + s - 1, s);
}
// 对右下角棋盘进行分治覆盖
if (dr >= tr + s && dc >= tc + s)
solve(tr + s, tc + s, dr, dc, s);
else {
board[tr + s][tc + s] = t;
solve(tr + s, tc + s, tr + s, tc + s, s);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int k = scanner.nextInt();
int x = scanner.nextInt();
int y = scanner.nextInt();
// 初始化棋盘
int size = 1 << k; // 棋盘大小为2^k
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
board[i][j] = -1;
// 设置特殊方格
board[x][y] = 0;
// 分治递归覆盖棋盘
solve(0, 0, x, y, size);
// 输出结果
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print(board[i][j] + "\t");
}
System.out.println();
}
scanner.close();
}
}
题目二合并排序问题
对n个元素组成的序列进行排序。
基本思想:将待排序元素分成大小大致相同的两个子集合,分别对两个集合进行排序,最终将排序好的子集合合并成所要求的排好序的集合。
C++版
#include <iostream>
using namespace std;
const int N = 1e5 + 10; // 数组的最大长度
int arr[N], tmp[N]; // 数组和临时数组
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else tmp[k ++ ] = q[j ++ ];
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> arr[i];
}
merge_sort(arr, 0, n - 1);
for (int i = 0; i < n; ++i) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
python版
def merge_sort(q, l, r):
"""
归并排序函数,使用分治的思想将数组分成两个子数组进行排序,然后合并这两个子数组。
:param q: 待排序的数组
:param l: 数组的左边界
:param r: 数组的右边界
"""
if l >= r: # 如果数组的长度小于等于 1,则不需要排序,直接返回
return
mid = (l + r) // 2 # 计算数组的中间位置
merge_sort(q, l, mid) # 递归排序左半部分
merge_sort(q, mid + 1, r) # 递归排序右半部分
i, j, k = l, mid + 1, 0 # 初始化指针 i 和 j 分别指向左半部分和右半部分的开头,k 记录 tmp 数组的指针位置
tmp = [0] * (r - l + 1) # 临时数组 tmp,用来存储合并后的结果
# 比较两个子数组的元素,将较小的元素放入 tmp 数组中
while i <= mid and j <= r:
if q[i] <= q[j]:
tmp[k] = q[i]
k += 1
i += 1
else:
tmp[k] = q[j]
k += 1
j += 1
# 将剩余的元素放入 tmp 数组中
while i <= mid:
tmp[k] = q[i]
k += 1
i += 1
while j <= r:
tmp[k] = q[j]
k += 1
j += 1
# 将 tmp 数组的元素复制回原数组中
for i in range(r - l + 1):
q[l + i] = tmp[i]
if __name__ == '__main__':
n = int(input()) # 输入数组的长度
arr = list(map(int, input().split())) # 输入数组的元素
merge_sort(arr, 0, n - 1) # 排序
for x in arr:
print(x, end=' ') # 输出排序后的数组
print()
Java版
import java.util.Scanner;
public class Main {
// 数组的最大长度
private static final int N = 100010;
// 数组和临时数组
private static int[] arr = new int[N];
private static int[] tmp = new int[N];
// 归并排序
private static void mergeSort(int[] q, int l, int r) {
// 当区间长度小于2时,退出递归
if (l >= r) return;
// 分治
int mid = l + r >> 1;
mergeSort(q, l, mid);
mergeSort(q, mid + 1, r);
// 合并
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r) {
if (q[i] <= q[j]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
}
while (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[j++];
// 更新原数组
for (i = l, j = 0; i <= r; i++, j++) {
q[i] = tmp[j];
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 输入数组元素
for (int i = 0; i < n; ++i) {
arr[i] = sc.nextInt();
}
// 归并排序
mergeSort(arr, 0, n - 1);
// 输出排序后的数组
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
题目三集合最大元问题
在规模为n的数据元素集合中找出最大元。当n=2时,一次比较就可以找出两个数据元素的最大元和最小元。当n>2时,可以把n个数据元素分为大致相等的两半,一半有n/2个数据元素,而另一半有n/2个数据元素。 先分别找出各自组中的最大元,然后将两个最大元进行比较,就可得n个元素的最大元
c++版
#include <iostream>
using namespace std;
int findMax(int arr[], int n) {
if (n == 1) {
return arr[0];
} else if (n == 2) {
return max(arr[0], arr[1]);
} else {
int mid = n / 2;
int leftMax = findMax(arr, mid);
int rightMax = findMax(arr + mid, n - mid);
return max(leftMax, rightMax);
}
}
int main() {
int n;
cin >> n;
int arr[n];
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
int maxNum = findMax(arr, n);
cout << maxNum << endl;
return 0;
}
python版
n = int(input()) # 输入数组长度
arr = list(map(int, input().split())) # 输入数组
def findMax(arr, n):
if n == 1:
return arr[0]
elif n == 2:
return max(arr[0], arr[1])
else:
mid = n // 2
leftMax = findMax(arr[:mid], mid)
rightMax = findMax(arr[mid:], n - mid)
return max(leftMax, rightMax)
maxNum = findMax(arr, n)
print(maxNum) # 输出最大值
java版
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int maxNum = findMax(arr, 0, n - 1);
System.out.println(maxNum);
}
public static int findMax(int[] arr, int left, int right) {
if (left == right) {
return arr[left];
} else {
int mid = (left + right) / 2;
int leftMax = findMax(arr, left, mid);
int rightMax = findMax(arr, mid + 1, right);
return Math.max(leftMax, rightMax);
}
}
}