算法设计与分析

第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;
}

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值