[NEFU 算法设计与分析]算法代码汇总
PPT 看代码太难受了,重新格式化和整理
懒得写回溯和分支限界了,就这样子吧
- 只包含 PPT 完整给出的算法 & 实验做的算法,没给的就没整理了
- 对标软工的要求(应该比计科和大数据简单)
- 主要进行了格式优化增加注释,非片段可运行
递归与分支策略
求阶乘
#include<bits/stdc++.h>
using namespace std;
int fac(int n) {
return n == 0 ? 1 : n * fac(n-1);
}
int main() {
cout << fac(10);
return 0;
}
求二叉树子节点数
#include <bits/stdc++.h>
using namespace std;
typedef struct node {
char data;
struct node *lchild, *rchild;
} BinNode, *BinTree;
int LeafCount(const BinTree &T) {
if (!T) {
return 0;
} else if (T->lchild == NULL && T->rchild == NULL) {
return 1;
} else {
return LeafCount(T->lchild) + LeafCount(T->rchild);
}
}
void CreateBinTree(BinTree &T){
char ch;cin>>ch;
if(ch=='@')T=NULL;
else{
T=new BinNode;
T->data=ch;
CreateBinTree(T->lchild);
CreateBinTree(T->rchild);
}
}
/*
输入 abc@@@d@e@@
a
/ \
b d
/ \ / \
c @ @ e
/\ / \
@ @ @ @
*/
int main() {
BinTree T = new BinNode;
CreateBinTree(T);
cout << LeafCount(T);
return 0;
}
汉诺塔
#include<bits/stdc++.h>
using namespace std;
int cnt;
void move(int id, char from, char to) {
printf ("step %d: move %d from %c->%c\n", ++cnt, id, from, to);
}
void hanoi(int n, char a, char b, char c) { //将 n 个碟子从 a 移到 b
if (n == 0) {
return;
} else {
hanoi(n - 1, a, c, b); //将 n-1 个碟子从 a 移到 c
move(n,a, b); //第 n 号 盘子 从 a 移到 b
hanoi(n - 1, c, b, a); //将 n-1 个碟子从 c 移到 b
}
}
int main() {
hanoi(3,'A','B','C');
return 0;
}
排列
#include <bits/stdc++.h>
using namespace std;
void Perm(int list[], int k, int m) {
if (k == m) {
for (int i = 0; i <= m; i++) {
cout << list[i];
}
cout << endl;
} else {
for (int i = k; i <= m; i++) {
swap(list[k], list[i]);
Perm(list, k + 1, m);
swap(list[k], list[i]);
}
}
}
int main() {
int list[4] = {1,2,3,4};
Perm(list,0,3);
return 0;
}
棋盘覆盖问题
#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
int board[N][N];
int tile;
void chessBoard(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) { // 覆盖左上角子棋盘
chessBoard(tr, tc, dr, dc, s); // 特殊方格在此棋盘中
} else { // 此棋盘中无特殊方格
board[tr + s - 1][tc + s - 1] = t; // 用 t 号L型骨牌覆盖右下角
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 { // 此棋盘中无特殊方格
board[tr + s - 1][tc + s] = t; // 用 t 号L型骨牌覆盖左下角
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 { // 用 t 号L型骨牌覆盖左下角
board[tr + s][tc + s - 1] = t; // 用 t 号L型骨牌覆盖右上角
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 {
board[tr + s][tc + s] = t; // 用 t 号L型骨牌覆盖左上角
chessBoard(tr + s, tc + s, tr + s, tc + s, s); // 覆盖其余方格
}
}
int k,dr,dc,size;
int main() {
while(cin >> k) { //k表示阶数
size = (1<<k); //2^k
cin >> dr >> dc; //dr,dc 标记特殊方块坐标
chessBoard(1,1,dr,dc,size);
for(int i = 1; i <= size; ++i) {
for(int j = 1; j <= size; ++j) {
cout<<setw(5)<<board[i][j];
}
cout<<endl;
}
}
return 0;
}
合并排序
#include <bits/stdc++.h>
using namespace std;
int b[105]; //临时存储合并结果
void Merge(int a[], int b[], int left, int mid, int right) { //合并两个有序数组
int p = left, q = mid+1;
int pos = 0;
while(p <= mid && q <= right) {
if(a[p] < a[q]) {
b[pos++] = a[p++];
} else {
b[pos++] = a[q++];
}
}
while(p <= mid) b[pos++] = a[p++];
while(q <= right) b[pos++] = a[q++];
}
void copy(int a[], int b[],int left,int right) {
for(int i = left; i <= right; ++i) {
a[i] = b[i-left];
}
}
void MergeSort(int a[], int left, int right) {
if (left < right) { //至少有2个元素
int i = (left + right) / 2; //取中点
MergeSort(a, left, i);
MergeSort(a, i + 1, right);
Merge(a, b, left, i, right); //合并到数组b
copy(a, b, left, right); //复制回数组a
}
}
int main() {
int a[] = {13,1,3,7,10,2};
MergeSort(a,0,5);
for(int i = 0; i < 6; ++i) {
cout << a[i] << " ";
}
return 0;
}
快速排序
#include <bits/stdc++.h>
using namespace std;
int Partition(int a[], int p, int r) {
int i = p, j = r + 1;
int x = a[p];
while (true) {
while (a[++i] < x && i < r); //i调整到 a[i] >= x
while (a[--j] > x && j > p); //j调整到 a[j] <= x
if (i >= j) {
break;
}
swap(a[i], a[j]);
}
a[p] = a[j];
a[j] = x;
return j;
}
void QuickSort(int a[], int p, int r) {
if (p < r) {
int q = Partition(a, p, r); //划分成3段 a[p,q-1] <= a[q] <= a[q+1,r]
QuickSort(a, p, q - 1); //对左半段排序
QuickSort(a, q + 1, r); //对右半段排序
}
}
int RandomizedPartition (int a[], int p, int r) {
int i = (rand()%(r-p+1)) +p; //生成 [p,r]的 随机数
swap(a[i], a[p]);
return Partition (a, p, r);
}
int main() {
int a[] = {2,10,7,3,1,13};
QuickSort(a,0,5);
for(int i = 0; i < 6; ++i) {
cout << a[i] << " ";
}
return 0;
}
循环赛日程表
#include <bits/stdc++.h>
using namespace std;
int a[105][105];
void Table(int k) {
int n = (1<<k); //2^k
for (int i = 1; i <= n; i++) { //初始化第一行
a[1][i] = i;
}
int m = 1; //控制填充的起始位置
for (int s = 1; s <= k; s++) {
n /= 2; //处理的矩阵数量 k 次减少 8->4->2->1
for (int t = 1; t <= n; t++) { //处理矩阵的数量
//[m+1,m+1]到[2m,2m]的,大小为 m* m 的矩阵
for (int i = m + 1; i <= 2 * m; i++) { //控制行
for (int j = m + 1; j <= 2 * m; j++) { //控制列
a[i][j + (t - 1) * m * 2] = a[i - m][j + (t - 1) * m * 2 - m]; //右下角等于左上角的值
a[i][j + (t - 1) * m * 2 - m] = a[i - m][j + (t - 1) * m * 2]; //左上角等于右下角的至
}
}
}
m *= 2; //处理的矩阵大小 k 次增长 1->2->4->8->....
}
}
int main() {
int k;cin>>k;
Table(k);
for(int i = 1; i <= (1<<k); ++i) {
for(int j = 1; j <= (1<<k); ++j) {
cout << a[i][j]<< " ";
}cout<<endl;
}
return 0;
}
动态规划算法
矩阵连乘问题
最优凸多边三角基本一样
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n,m;
int dp[N][N],s[N][N]; // s[l][r] 记录[l,r]最优分割点
int p[N];
void MatrixChain() {
for (int i = 1; i <= n; i++) { //初始化
dp[i][i] = 0;
}
for (int len = 2; len <= n; len++) //长度
for (int l = 1; l + len -1 <= n; l++) { //左边界
int r = l + len - 1; //右边界
dp[l][r] = dp[l + 1][r] + p[l - 1] * p[l] * p[r]; //计算耗费
s[l][r] = l; //初始化最优分割点
for (int k = l + 1; k < r; k++) { //枚举分割点 [l,k] [k+1][r]
int t = dp[l][k] + dp[k + 1][r] + p[l - 1] * p[k] * p[l];
if (t < dp[l][r]) {
dp[l][r] = t; //更新最小耗费
s[l][r] = k; //更新最优分割点
}
}
}
}
//回溯输出方案
void TraceBack(int l,int r) {
if (l == r) return ;
int k = s[l][r]; //[l,r] 区间最优分割点 k
TraceBack(l, k);
TraceBack(k + 1, r);
cout << "Multiply A" << l << "," << k
<< "and A" << k + 1 << "," << r << endl;
}
//递归法
int RecurMatrixChain(int l, int r) {
if (l == r) return 0;
int u = RecurMatrixChain(l, l) + RecurMatrixChain(l + 1, r) + p[l - 1] * p[l] * p[r];
s[l][r] = l;
for (int k = l + 1; k < r; k++) {
int t = RecurMatrixChain(l, k) + RecurMatrixChain(k + 1, r) + p[l - 1] * p[k] * p[r];
if (t < u) {
u = t;
s[l][r] = k;
}
}
return u;
}
//备忘录
int LookupChain(int l, int r) {
if (dp[l][r] > 0) return dp[l][r];
if (l == r) return 0;
int u = LookupChain(l, l) + LookupChain(l + 1, r) + p[l - 1] * p[l] * p[r];
s[l][r] = l;
for (int k = l + 1; k < r; k++) {
int t = LookupChain(l, k) + LookupChain(k + 1, r) + p[l - 1] * p[k] * p[r];
if (t < u) {
u = t;
s[l][r] = k;
}
}
return dp[l][r] = u;
}
/* 输入
6
30 35 15 5 10 20 25
*/
int main() {
cin >> n;
for(int i = 0; i <=n; ++i) {
cin >> p[i];
}
MatrixChain();
cout << "MatrixChain: " << dp[1][n] << endl;
cout << endl;
TraceBack(1, n);
cout << endl;
memset(dp,0,sizeof dp); //清空 dp
memset(s,0,sizeof s); //清空 s
cout << "RecurMatrixChain: " << RecurMatrixChain(1, n) << endl;
cout << endl;
TraceBack(1, n);
cout << endl;
memset(dp,0,sizeof dp); //清空 dp
memset(s,0,sizeof s); //清空 s
cout << "LookupChain: " << LookupChain(1, n) << endl;
cout << endl;
TraceBack(1, n);
cout << endl;
return 0;
}
最长公共子序列
实验指导书
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
char A[N],B[N];
int from[N][N];
int dp[N][N];
int n,m;
void LCSLength(int n, int m) {
//初始化
for (int i = 1; i <= n; i++) {
dp[i][0] = 0;
}
for (int i = 1; i <= m; i++) {
dp[0][i] = 0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A[i] == B[j]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
from[i][j] = 1;
} else if (dp[i - 1][j] >= dp[i][j - 1]) {
dp[i][j] = dp[i - 1][j];
from[i][j] = 2;
} else {
dp[i][j] = dp[i][j - 1];
from[i][j] = 3;
}
}
}
}
//构造
void LCS(int i, int j) {
if (i == 0 || j == 0) return;
if (from[i][j] == 1) {
LCS(i - 1, j - 1);
cout << A[i];
} else if (from[i][j] == 2) {
LCS(i - 1, j);
} else {
LCS(i, j - 1);
}
}
int main() {
scanf("%d %d",&n, &m);
scanf("%s %s",A+1,B+1);
LCSLength(n, m);
LCS(n,m);
return 0;
}
/* 输入
7 6
ABCBDAB
BDCABA
*/
01背包问题
不是课件上的递推方程,是下面的,考试用的话最好写清楚
d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ j ] j < w [ i ] d p [ i − 1 ] [ j − w [ i ] ] + v [ i ] j > = w [ i ] dp[i][j]= max\left\{ \begin{aligned} dp[i-1][j] & & j < w[i] \\ dp[i-1][j-w[i]] + v[i] & & j>= w[i] \end{aligned} \right. dp[i][j]=max{dp[i−1][j]dp[i−1][j−w[i]]+v[i]j<w[i]j>=w[i]
#include<bits/stdc++.h>
using namespace std;
const int N = 105 ,M = 1005;
int n,m; // n 物品数量,m 背包容量
int w[N],v[N]; // weight,value
int dp[N][M];
void solve() {
for(int i = 1; i <= n; ++i) {
for(int j = 0; j <= m; ++j) {
if(j < w[i] ) dp[i][j] = dp[i-1][j]; //装不下,只能不选
else { //比较选第i个物品和不选第i个物品
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]] + v[i]);
}
}
}
}
void traceBack() { //回溯求具体方案
int j = m; //最后状态 (?,m)
for(int i = n; i>= 1; i--) { //逆推找从哪个转移来的
if(j >= w[i] && dp[i][j] == dp[i-1][j-w[i]] + v[i]) {
cout << "choose " << i << endl;
j -= w[i];
}
}
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; ++i) {
cin >> w[i] >> v[i];
}
solve();
cout <<"solve: " << dp[n][m] << endl;
traceBack();
return 0;
}
/*
输入
n m
5 10
w v
2 6
2 3
6 5
5 4
4 6
*/
数字三角形
实验指导书的
#include<stdio.h>
#define ll long long
#define N 105
ll f[N][N],w[N][N];
ll max(ll a,ll b){return a>b?a:b;}
int n;
void print(int x,int y){
if(x<1||y<1||x>n||y>n||x<y)return;
if(f[x-1][y] > f[x-1][y-1]) {
print(x-1,y);
} else {
print(x-1,y-1);
}
printf("%lld ",w[x][y]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
scanf("%lld",&w[i][j]);
}
}
//初始化:
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
f[i][j]=-1e9;
}
}
f[1][1]=w[1][1];
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
f[i][j]=max(f[i][j],f[i-1][j]+w[i][j]);
f[i][j]=max(f[i][j],f[i-1][j-1]+w[i][j]);
}
}
ll ans=-1e9;
int x = n,y;
for(int i=1;i<=n;i++){
if(f[n][i] > ans) {
ans = f[n][i];
y = i;
}
}
printf("%lld\n",ans);
print(x,y);
return 0;
}
贪心算法
活动安排问题
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n,t;
int s[N],f[N];
void solve() {
if(f[1] > t)return;
cout <<"choose: 1 ";
int j = 1;
for(int i = 2; i <= n; ++i) {
if(s[i] >= f[j]) {
cout << i << " ";
j = i;
}
}
}
int main() {
cin >> n >> t;
for(int i = 1; i <=n ; ++i) {
cin >> s[i] >> f[i];
}
solve();
return 0;
}
/*输入
10 11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
*/
最优装载问题
#include <bits/stdc++.h>
using namespace std;
int n,c;
vector<pair<int,int>> Container; //first 为重量,second为初始位置
void Loading() {
sort(Container.begin(),Container.end()); //按重量从小到大排序
for (int i = 0 ; i < n && Container[i].first <= c; i++) {
cout << "choose: " << Container[i].second << endl;
c -= Container[i].first;
}
}
int main(){
cin >> n >> c;
for(int i = 1 , w; i<= n; ++i) {
cin >> w;
Container.push_back({w,i});
}
Loading();
return 0;
}