[NEFU算法设计与分析] 代码汇总

[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[i1][j]dp[i1][jw[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;
}
  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值