第2章 分治
1、棋盘覆盖
// 棋盘覆盖
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int tile = 0, board[105][105];
void chessBoard(int tr, int tc, int dr, int dc, int size)
{
if (size == 1){
return ;
}
int t = ++tile;
int s = size / 2;
if (dr < tr + s and dc < tc + s){
chessBoard(tr, tc, dr, dc, s);
}else{
board[tr + s - 1][tc + s -1] = t;
chessBoard(tr, tc, tr + s - 1, tc + s - 1, s);
}
if (dr < tr + s and dc >= tc + s){
chessBoard(tr, tc + s, 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 and dc < tc + s){
chessBoard(tr + s, tc, dr, dc, s);
}else{
board[tr + s][tc + s - 1] = t;
chessBoard(tr + s, tc, tr + s, tc + s - 1, s);
}
if (dr >= tr + s and dc >= tc + s){
chessBoard(tr + s, tc + s, dr, dc, s);
}else{
board[tr + s][tc + s] = t;
chessBoard(tr + s, tc + s, tr + s, tc + s, s);
}
}
int main()
{
int dr, dc, n;
cin>>dr>>dc>>n;
int size = pow(2, n);
chessBoard(1, 1, dr, dc, size);
for (int i = 1; i <= size; i++){
for(int j = 1; j <= size; j++){
cout<<board[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
2、归并排序
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int a[10005], b[10005], n;
void merge(int left, int mid, int right)
{
int i = left, j = mid + 1, k = left;
while(i <= mid and j <= right){
if(a[i] <= a[j]){
b[k] = a[i];
i++;
}else{
b[k] = a[j];
j++;
}
k++;
}
while(i <= mid){
b[k++] = a[i++];
}
while(j <= right){
b[k++] = a[j++];
}
for(int i = left; i <= right; i++){
a[i] = b[i];
}
}
void merge_sort(int left, int right)
{
if(left < right){
int mid = (left + right) / 2;
merge_sort(left, mid);
merge_sort(mid + 1, right);
merge(left, mid, right);
}
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
}
merge_sort(1, n);
for(int i = 1; i <= n; i++){
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
3、快速排序
#include<iostream>
using namespace std;
int a[1005], n;
int partition(int low, int high)
{
int i = low, j = high;
int x = a[low];
while(i != j){
while(a[j] >= x and i < j) j--;
while(a[i] <= x and i < j) i++;
swap(a[i], a[j]);
}
swap(a[i], a[low]);
return i;
}
void quick_sort(int p, int r)
{
if(p < r){
int q = partition(p, r);
quick_sort(p, q - 1);
quick_sort(q + 1, r);
}
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
}
quick_sort(1, n);
for(int i = 1; i <= n; i++){
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
4、循环赛日程表
#include<iostream>
using namespace std;
int a[105][105];
void solve(int r, int c, int l, int v)
{
if (l == 1) {
a[r][c] = v;
return ;
}
int mid = l / 2;
solve(r, c, mid, v);
solve(r + mid, c, mid, v + mid);
solve(r, c + mid, mid, v + mid);
solve(r + mid, c + mid, mid, v);
}
int main()
{
int n;
cin>>n;
solve(1, 1, n, 1);
for (int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
5、整数因子分解(重复)
#include<bits/stdc++.h>
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);
}
}
int main()
{
int n;
total = 0;
cin>>n;
solve(n);
cout<<total<<endl;
return 0;
}
6、整数因子分解(去重)
#include<bits/stdc++.h>
using namespace std;
int total;
void solve(int n, int start) {
if (n == 1){
total++;
}else {
for (int i = start; i <= n; i++)
if (n % i == 0) solve(n / i, i);
}
}
int main()
{
int n;
total = 0;
cin>>n;
solve(n, 2);
cout<<total<<endl;
return 0;
}
7、全排列
#include<iostream>
using namespace std;
int n, x[105];
void perm(int t)
{
if(t > n){
for(int i = 1; i <= n; i++){
cout<<x[i]<<" ";
}
cout<<endl;
return ;
}
for(int i = t; i <= n; i++){
swap(x[t], x[i]);
perm(t + 1);
swap(x[t], x[i]);
}
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++){
x[i] = i;
}
perm(1);
return 0;
}
8、汉诺塔
// a移到b
#include<iostream>
using namespace std;
void hanoi(int n, char a, char b, char c)
{
if(n > 0){
hanoi(n-1, a, c, b);
cout<<a<<"--->"<<b<<endl;
hanoi(n-1, c, b, a);
}
}
int main()
{
int n;
cin>>n;
hanoi(n, 'a', 'b', 'c');
return 0;
}
// a移到c
#include<iostream>
using namespace std;
void hanoi(int n, char a, char b, char c)
{
if(n > 0){
hanoi(n-1, a, c, b);
cout<<a<<"--->"<<c<<endl;
hanoi(n-1, b, a, c);
}
}
int main()
{
int n;
cin>>n;
hanoi(n, 'a', 'b', 'c');
return 0;
}
第3章 动态规划
1、矩阵连乘
#include<iostream>
using namespace std;
int p[1005], dp[1005][1005], n, s[1005][1005];
void Traceback(int i, int j) // 打印最优解
{
if (i == j) return ;
Traceback(i, s[i][j]);
Traceback(s[i][j] + 1, j);
cout<<"Multiply A "<<i<<", "<<s[i][j];
cout<<" and A "<<(s[i][j] + 1)<<", "<<j<<endl;
return ;
}
int main()
{
cin>>n;
for(int i = 0; i <= n; i++){
cin>>p[i];
}
for(int i = 1; i <= n; i++){
dp[i][i] = 0;
}
for(int r = 2; r <= n; r++){
for(int i = 1; i <= n - r + 1; i++){
int j = i + r - 1;
dp[i][j] = dp[i+1][j] + p[i-1] * p[i] * p[j];
s[i][j] = i;
for (int k = i + 1; k < j; k++){
int t = dp[i][k] + dp[k+1][j] + p[i-1] * p[k] * p[j];
if (t < dp[i][j]){
dp[i][j] = t;
s[i][j] = k;
}
}
}
}
cout<<dp[1][n]<<endl;
Traceback(1, n);
return 0;
}
/*
6
30 35 15 5 10 20 25
*/
2、01背包
#include<iostream>
using namespace std;
struct node{
int weight, value;
}nodes[1005];
int dp[105][105];
int main()
{
int n, w;
cin>>n>>w;
for(int i = 1; i <= n; i++){
cin>>nodes[i].weight>>nodes[i].value;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= w; j++){
if (j < nodes[i].weight){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = max(dp[i-1][j], dp[i-1][j - nodes[i].weight] + nodes[i].value);
}
}
}
cout<<dp[n][w]<<endl;
return 0;
}
3、最长公共子序列
#include<iostream>
using namespace std;
string s1, s2;
int dp[1005][1005];
int main()
{
cin>>s1>>s2;
int l1 = s1.size(), l2 = s2.size();
for(int i = 1; i <= l1; i++){
for(int j = 1; j <= l2; j++){
if (s1[i - 1] == s2[j - 1]){
dp[i][j] = dp[i-1][j-1] + 1;
}else{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
cout<<dp[l1][l2]<<endl;
return 0;
}
4、最大字段和
#include<iostream>
using namespace std;
int dp[1005], x[1005], maxsum = 0;
int main()
{
int n;
cin>>n;
for(int i = 1; i <= n; i++){
cin>>x[i];
}
for(int i = 1; i <= n; i++){
dp[i] = max(dp[i-1] + x[i], x[i]);
if(dp[i] > maxsum){
maxsum = dp[i];
}
}
cout<<maxsum<<endl;
return 0;
}
5、最长上升子序列
#include<bits/stdc++.h>
using namespace std;
int dp[10005], a[10005];
int main()
{
int n;
cin>>n;
for (int i = 1; i <= n; i++) cin>>a[i];
for (int i = 1; i <= n; i++){
dp[i] = 1;
for (int j = 1; j < i; j++){
if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);
}
}
int res = 0;
for (int i = 1; i <= n; i++){
res = max(res, dp[i]);
}
cout<<res<<endl;
return 0;
}
/*
7
1 7 3 5 9 4 8
*/
6、01背包(扩展)
#include<bits/stdc++.h>
using namespace std;
int dp[105][105][105], w[105], b[105], v[105];
int main()
{
int n, weight, volume;
cin>>n>>weight>>volume;
for (int i = 1; i <= n; i++){
cin>>w[i]>>b[i]>>v[i];
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= weight; j++){
for (int k = 1; k <= volume; k++){
if (j >= w[i] and k >= b[i]){
dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-w[i]][k-b[i]] + v[i]);
}else{
dp[i][j][k] = dp[i-1][j][k];
}
}
}
}
cout<<dp[n][weight][volume]<<endl;
return 0;
}
/*
20 15 3
11 7 9
9 5 10
7 10 5
*/
第4章 贪心算法
1、最优装载
#include<iostream>
#include<algorithm>
using namespace std;
int a[1005];
int main()
{
int n, c;
cin>>n>>c;
for(int i = 1; i <= n; i++){
cin>>a[i];
}
sort(a + 1, a + n + 1);
int cnt = 0;
for(int i = 1; i <= n; i++){
if (a[i] <= c){
cnt++;
c -= a[i];
}
}
cout<<cnt<<endl;
return 0;
}
2、活动安排
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int start, end;
}nodes[1005];
bool cmp(struct node s1, struct node s2)
{
return s1.end < s2.end;
}
int main()
{
int n;
cin>>n;
for(int i = 1; i <= n; i++){
cin>>nodes[i].start>>nodes[i].end;
}
sort(nodes + 1, nodes + 1 + n, cmp);
int cnt = 1, r = nodes[1].end;
for(int i = 2; i <= n; i++){
if (nodes[i].start >= r){
cnt++;
r = nodes[i].end;
}
}
cout<<cnt<<endl;
return 0;
}
3、Dijkstra算法
#include<iostream>
using namespace std;
const int inf = 0x3f3f3f;
int a[1005][1005], dis[1005], vis[1005];
int nodes, edges;
void dijkstra(int x)
{
fill(dis + 1, dis + nodes + 1, inf);
vis[x] = 1;
dis[x] = 0;
for(int i = 1; i <= nodes; i++){
dis[i] = a[1][i];
}
for(int i = 1; i < nodes; i++){
int j = 1, mindis = inf;
for(int k = 1; k <= nodes; k++){
if(!vis[k] and dis[k] < mindis){
mindis = dis[k];
j = k;
}
}
vis[j] = 1;
for(int k = 1; k <= nodes; k++){
if(!vis[k] and dis[j] + a[j][k] < dis[k]){
dis[k] = dis[j] + a[j][k];
}
}
}
return ;
}
int main()
{
cin>>nodes>>edges;
for(int i = 1; i <= edges; i++){
int from, end, d;
cin>>from>>end>>d;
a[from][end] = d;
a[end][from] = d;
}
dijkstra(1);
for(int i = 1; i <= nodes; i++){
cout<<dis[i]<<" ";
}
cout<<endl;
return 0;
}
/*
4 6
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
*/
4、Prim算法
#include<iostream>
using namespace std;
const int inf = 0x3f3f3f;
int a[1005][1005], dis[1005], vis[1005];
int nodes, edges, ans;
void prim(int x)
{
fill(dis + 1, dis + nodes + 1, inf);
vis[x] = 1;
dis[x] = 0;
for(int i = 1; i <= nodes; i++){
dis[i] = a[1][i];
}
for(int i = 1; i < nodes; i++){
int j = 1, mindis = inf;
for(int k = 1; k <= nodes; k++){
if(!vis[k] and dis[k] < mindis){
mindis = dis[k];
j = k;
}
}
ans += mindis;
vis[j] = 1;
for(int k = 1; k <= nodes; k++){
if(!vis[k] and a[j][k] < dis[k]){
dis[k] = a[j][k];
}
}
}
return ;
}
int main()
{
cin>>nodes>>edges;
for(int i = 1; i <= edges; i++){
int from, end, d;
cin>>from>>end>>d;
a[from][end] = d;
a[end][from] = d;
}
prim(1);
cout<<ans<<endl;
return 0;
}
/*
4 6
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
*/
5、Kruskal算法
#include<iostream>
#include<algorithm>
using namespace std;
struct edge{
int from, to, w;
}edges[1005];
int pre[1005], ans;
int find(int x) // 查找根元素,并查集
{
if(pre[x] != x){
pre[x] = find(pre[x]);
}
return pre[x];
}
bool cmp(struct edge s1, struct edge s2)
{
return s1.w < s2.w;
}
int main()
{
int n, edge_num;
cin>>n>>edge_num;
for(int i = 1; i <= edge_num; i++){
cin>>edges[i].from>>edges[i].to>>edges[i].w;
}
for(int i = 1; i <= n; i++){
pre[i] = i;
}
sort(edges + 1, edges + edge_num + 1, cmp);
for(int i = 1; i <= edge_num; i++){
int a = find(edges[i].from);
int b = find(edges[i].to);
if(a != b){
ans += edges[i].w;
pre[b] = a;
}
}
cout<<ans<<endl;
return 0;
}
第5章 回溯法
1、全排列
#include<iostream>
using namespace std;
int n, x[1005], vis[1005];
void backtrack(int t)
{
if (t > n){
for (int i = 1; i <= n; i++){
cout<<x[i]<<" ";
}
cout<<endl;
return ;
}
for(int i = 1; i <= n; i++){
if(!vis[i]){
x[t] = i;
vis[i] = 1;
backtrack(t + 1);
vis[i] = 0;
}
}
}
int main()
{
cin>>n;
backtrack(1);
return 0;
}
/*
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
*/
2、01背包
#include<bits/stdc++.h>
using namespace std;
struct node{
int w;
int v;
}nodes[1005];
int wr, vw, bestvw, w, n, c;
void backtrack(int i)
{
if (i > n){
if(vw > bestvw){
bestvw = vw;
}
return ;
}
if (wr + nodes[i].w <= c){
wr += nodes[i].w;
vw += nodes[i].v;
backtrack(i + 1);
wr -= nodes[i].w;
vw -= nodes[i].v;
}
backtrack(i + 1);
}
int main()
{
cin>>n>>c;
for(int i = 1; i <= n; i++){
cin>>nodes[i].w>>nodes[i].v;
}
backtrack(1);
cout<<bestvw<<endl;
return 0;
}
/*
4 7
1 1
3 4
4 5
5 7
9
*/
3、n皇后
#include<iostream>
#include<cmath>
using namespace std;
int x[1005], n, sum;
bool judge(int t)
{
for(int i = 1; i < t; i++){
if(x[i] == x[t] || t - i == abs(x[t] - x[i])){
return false;
}
}
return true;
}
void backtrack(int t)
{
if(t > n){
sum++;
return ;
}
for(int i = 1; i <= n; i++){
x[t] = i;
if(judge(t)){
backtrack(t + 1);
}
}
}
int main()
{
cin>>n;
backtrack(1);
cout<<sum<<endl;
return 0;
}
4、符号三角形
#include<iostream>
using namespace std;
int x[1005][1005], n, res, sum;
void backtrack(int t)
{
if(t > n){
int cnt = 0;
for(int i = 2; i <= n; i++){
for(int j = 1; j <= n - i + 1; j++){
x[i][j] = x[i-1][j] * x[i-1][j+1];
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n-i+1; j++){
if(x[i][j] == 1){
cnt++;
}
}
}
if (cnt == sum / 2){
res++;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n - i + 1; j++){
x[i][j] == 1 ? cout<<"+"<<" " : cout<<"-"<<" ";
}
cout<<endl;
}
cout<<endl;
}
return ;
}else{
for(int i = -1; i <= 1; i+=2){
x[1][t] = i;
backtrack(t+1);
}
}
}
int main()
{
cin>>n;
sum = (n * (n + 1)) / 2;
if(sum % 2 == 0){
backtrack(1);
cout<<res<<endl;
}else{
cout<<0<<endl;
}
return 0;
}
5、装载问题
#include<iostream>
using namespace std;
int w[1005], cw, n, c, bestcw;
void backtrack(int t)
{
if(t > n){
if(cw > bestcw){
bestcw = cw;
}
return ;
}
if(cw + w[t] <= c){
cw += w[t];
backtrack(t + 1);
cw -= w[t];
}
backtrack(t+1);
}
int main()
{
cin>>n>>c;
for(int i = 1; i <= n; i++){
cin>>w[i];
}
backtrack(1);
cout<<bestcw<<endl;
return 0;
}
/*
6 100
20 15 20 35 45 1
*/
其他
1、二分搜索
#include<iostream>
using namespace std;
int a[1005], n;
int binary_search(int x)
{
int low = 1, high = n;
while(low <= high){
int mid = (low + high) / 2;
if(a[mid] == x){
return mid;
}else if(a[mid] < x){
low = mid + 1;
}else{
high = mid - 1;
}
}
return -1;
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
}
cout<<binary_search(10)<<endl; // 查找数字10
return 0;
}
/*
10
1 3 6 10 11 15 17 19 20 25
*/
2、阶乘和Fibonacci数列
// 阶乘
#include<iostream>
using namespace std;
int f(int n)
{
if (n == 1) return 1;
return n * f(n-1);
}
int main()
{
int n;
cin>>n;
cout<<f(n)<<endl;
return 0;
}
// Fibonacci数列
#include<iostream>
using namespace std;
int fibonacci(int n)
{
if(n == 1 or n == 0) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
int main()
{
int n;
cin>>n;
cout<<fibonacci(n)<<endl;
return 0;
}
3、Ackerman函数
#include<iostream>
using namespace std;
int Ackerman(int m,int n){
int q;
if(m == 0)
return n+1;
else if(n == 0)
return Ackerman(m-1,1);
else{
return Ackerman(m-1,Ackerman(m,n-1));
}
}
int main()
{
int n, m;
cin>>n>>m;
cout<<Ackerman(n, m)<<endl;
return 0;
}
4、整数划分问题
#include<iostream>
using namespace std;
int q(int n, int m)
{
if (n < 1 or m < 1) return 0;
if (n == 1 or m == 1) return 1;
if (n < m) return q(n, n);
if(n == m) return 1 + q(n, m-1);
return q(n, m-1) + q(n - m, m);
}
int main()
{
int n, m;
cin>>n>>m;
cout<<q(n, m)<<endl;
return 0;
}