【期末复习】

这学期大致涉及到的都在这了,缺少的发在评论吧 ,有时间会补上。

递归和分治

合并排序

#define MAXSIZE 100
//合并函数 
void Merge(int a[], int low, int mid, int high) {
	int temp[MAXSIZE];
	int i=low, j=mid, p=low;
	while(i<mid && j<=high) {
		if(a[i]<a[j]) temp[p++]=a[i++];
		else temp[p++]=a[j++];
	}
	while(i<mid) temp[p++]=a[i++];
	while(j<=high) temp[p++]=a[j++];
	for(int i=low; i<=high; i++) {
		a[i]=temp[i];
	}
}
//归并排序主函数 
void MergeSort(int a[], int low, int high) {
	if(low<high) {
		int mid=(low+high)/2;
		MergeSort(a, low, mid);
		MergeSort(a, mid+1, high);
		Merge(a, low, mid+1, high);
	}
}

快速排序

int getmid(int a[],int l,int r){
	int mid = l;
	while(l != r){
		while(a[r] >= a[mid] && l < r) r--;
		while(a[l] <= a[mid] && l < r) l++;
		if(l < r) {
			swap(a[l],a[r]); 
		}
	} 
	swap(a[mid],a[l]);
	return l;
}
void quick_sort(int l , int r,int a[]){
	if(l < r){
		int mid = getmid(a,l,r);
		quick_sort(l,mid,a);
		quick_sort(r,mid,a);
	}
}

动态规划

矩阵连乘

给定n个矩阵:A1,A2,…,An,其中Ai与Ai+1是可乘的,i=1,2…,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。

#include <bits/stdc++.h>  
using namespace std ;  
typedef long long ll;  
typedef unsigned long long ull;  
const int maxn = 2e3 + 10;  
const int INF = 0x3f3f3f3f;  
const double eps = 1e-11;  
const ll mod = 1e9 + 7;  
int n;  
int dp[maxn][maxn];  
int s[maxn][maxn];  
int a[maxn];  
void matrixMultiply(){  
	for(int i = 1 ; i <= n ; i++) dp[i][i] = 0;  
	for(int r = 2 ; r <= n ; r++){//guimo  
		for(int i = 1 ; i <= n-r+1 ; i++){  
			int j = i + r - 1;  
			dp[i][j] = INF;  
			for(int k = i ;k <= j-1 ;k++){  
				int q = dp[i][k] + dp[k+1][j] + a[i-1] * a[k] * a[j];  
				if(q < dp[i][j]){  
					s[i][j] = k;  
					dp[i][j] = q;  
				}  
			}  
		}   
	}  
}  
void print(int i, int j) {    
    if (i == j) {    
        cout << "A" << i;    
    } else {    
        cout << "(";    
        print( i, s[i][j]);    
        print( s[i][j] + 1, j);    
        cout << ")";    
    }    
}    
int main(){  
	cin >> n ;  
	for(int i = 0 ; i <= n ; i++){//n个矩阵有n+1个数   
		cin >> a[i];  
	}  
	matrixMultiply(); // 计算最小乘法次数和最优的矩阵连乘方式  
	cout << dp[1][n] << endl;  
	print(1,n-1);  
	  
}  

最长公共子序列

#include <bits/stdc++.h>  
using namespace std ;  
typedef long long ll;  
typedef unsigned long long ull;  
const int maxn = 2e3 + 10;  
const int INF = 0x3f3f3f3f;  
const double eps = 1e-11;  
const ll mod = 1e9 + 7;  
string a , b; 
int m[maxn][maxn];

int main(){  
	cin >> a >> b;
	for(int i = 0 ; i < a.size() ; i++){
		for(int j = 0 ; j < b.size() ; j++){
			if(a[i] == b[j]){
				m[i+1][j+1] = m[i][j] + 1;
			}
			else{
				m[i+1][j+1] = max(m[i][j+1],m[i+1][j]);
			}
		}
	}
	cout << m[a.size()][b.size()] << endl;
	string lcs = ""; 
	int x , y ;  
	x = a.size();  
	y = b.size();  
	while(x > 0 && y > 0){  
	    if(a[x-1] == b[y-1]){  
	    	lcs = a[x-1] + lcs;  
	        x--;  
			y--;  
	    }   
	    else if(m[x-1][y] > m[x][y-1]){  
	        x--;  
	    }  
	    else{  
	        y--;  
	    }  
	}  
	cout << lcs << endl;
}  

最大子段和

题目:给定由n个整数组成的序列(a1,a2, …,an),求该序列形如的子段和的最大值,当所有整数均为负整数时,其最大子段和为0。

DP法:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int a[maxn];
int main(){
	int n;
	cin >> n;
	for(int i = 0 ; i < n ; i++){
		cin >> a[i];
	}
	int mx = 0 ;
	int p = 0;
	for(int i = 0 ; i < n ; i++){
		p = max(a[i],a[i]+p);
		mx = max(p,mx);
	}
	cout << mx << endl;
}

二分法:

PS:需要考虑跨越中点的最大子段和

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;
int a[maxn];
int n ;
int f(int l , int r){
	if(l >= r) return max(0,a[r]);
	int mid = (l + r) >> 1;
	int lmax = f(l,mid);
	int rmax = f(mid+1,r);
	int sum1 , sum2,max1,max2;
	sum1 = sum2 = 0 ;
	max1 = max2 = 0;
	for(int i = mid ; i >= l ; i--){
		sum1 += a[i];
		max1 = max(max1,sum1);
	}
	for(int i = mid + 1 ; i <= r ; i++){
		sum2 += a[i];
		max2 = max(max2,sum2);
	}
	return max(lmax,max(rmax,max1+max2));
	
}
int main(){
	cin >> n;
	for(int i = 0 ; i < n ; i++) cin >> a[i];
	cout << f(0,n-1) << endl;
}

贪心算法

活动安排

#include <bits/stdc++.h>  
using namespace std ;  
typedef long long ll;  
typedef unsigned long long ull;  
const int maxn = 2e3 + 10;  
const int INF = 0x3f3f3f3f;  
const double eps = 1e-11;  
const ll mod = 1e9 + 7; 
struct node {
	int start, ed;
}a[maxn];
int b[maxn];
int n;
bool cmp(node x, node y){
	return x.ed < y.ed;
}
int main(){
	cin >> n; 
	for(int i = 0; i < n ; i++){
		cin >> a[i].start >> a[i].ed;
	}
	sort(a,a+n,cmp);
	int f = 0;
	for(int i = 0 ; i < n ; i++){
		if(f){
			b[i] = 0;
		}
		else  b[i] = 1;
		
	}
}

单源最短路径

#include <bits/stdc++.h>  
using namespace std ;  
typedef long long ll;  
typedef unsigned long long ull;  
const int maxn = 2e3 + 10;  
const int INF = 0x3f3f3f3f;  
const double eps = 1e-11;  
const ll mod = 1e9 + 7; 
int n;  
int a[maxn][maxn]; 
int vis[maxn]; 
int dis[maxn]; 
void dij(int x) {  
    for (int i = 0; i < n; i++) {  
        dis[i] = INF;  
        vis[i] = 0;  
    }  
    dis[x] = 0; 
    for (int i = 0; i < n - 1; i++) {  
        int mn = INF, u;  
        for (int j = 0; j < n; j++) {  
            if (!vis[j] && dis[j] <= mn) {  
                mn = dis[j];  
                u = j;  
            }  
        }  
        vis[u] = 1; 
        for (int j = 0; j < n; j++) {  
            if (!vis[j] && a[u][j] && dis[u] != INF && dis[u] + a[u][j] < dis[j]) {  
                dis[j] = dis[u] + a[u][j];  
            }  
        }  
    }  
}  
  
int main() {  
    cin >> n; 
    for (int i = 0; i < n; i++) {  
        for (int j = 0; j < n; j++) {  
            a[i][j] = INF; 
        }  
    }  
    for (int i = 0; i < n; i++) {  
        int x, y, v;  
        cin >> x >> y >> v; 
        a[x][y] = a[y][x] = v; 
    }  
    dij(0); 
    return 0;  
}  

回溯

N皇后问题

不在重复,往期有

符号问题

#include <bits/stdc++.h>  
using namespace std ;  
typedef long long ll;  
typedef unsigned long long ull;  
const int maxn = 2e3 + 10;  
const int INF = 0x3f3f3f3f;  
const double eps = 1e-11;  
const ll mod = 1e9 + 7; 
int a[maxn][maxn];
int n;
int sum;
int ans;
void dfs(int x){
	if(x >= n){
		int c = 0 ;
		for(int i = 1 ; i < n ; i++){
			for(int j = 0 ; j < n - i ; j++) {
				a[i][j] = a[i-1][j] * a[i-1][j+1];
			}
		}
		for(int i = 0 ; i < n ; i++){
			for(int j = 0 ; j < n - i ; j++){
				if(a[i][j] == 1) c++;
			}
		}
		if(c*2 == sum){
			ans++;
			for(int i = 0 ; i < n ; i++){
				for(int j = 0 ; j < n - i ; j++){
					if(a[i][j] == 1) cout << " +";
					else  cout << " -";
				}
				cout << endl;
			}
		}
		return;
	}
	for(int i = -1 ; i <= 1 ; i+=2){
		a[0][x] = i;
		dfs(x+1);
	}
}
int main(){
	ans = 0 ;
	cin >> n ;
	sum = n*(n+1)/2;
	dfs(0);
	cout << ans << endl;
}

序列重排

题目:数组变量a 记录着一个长度为n 的序列a[0],a[2], …, a[n-1]。现在需要一个函数,以整数p (1≤ pn)为参数,实现如下功能:将序列ap个数与后np个数对调,且不改变这p 个数(或np 个数)之间的相对位置。例如,长度为5 的序列1, 2, 3, 4, 5,当p = 2 时重排结果为3,4, 5, 1, 2。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int a[maxn];
int b[maxn];
int main(){
	int n ;int k ;
	cin  >> n  >> k;
	for(int i = 0 ; i < n ; i++) cin >> a[i];
	for(int i = 0 ; i < n ; i++){
		b[i]= a[(i+k)%n]   ;
	}
	for(int i = 0 ; i < n ; i++){
		cout << b[i] << " " ; 
	}
	
}

斐波那契数列

题目:迭代算法与递归算法的效率分析

递归算法:

优点:简单易懂,直接表达了斐波那契数列的定义。

缺点:效率较低,存在大量的重复计算,导致指数级的时间复杂度。当计算较大的斐波那契数时,递归算法会非常慢。

迭代算法:

优点:效率更高,没有递归调用的开销,线性时间复杂度,计算速度快。

缺点:代码相对复杂一些,不如递归算法直观。但是,通过使用迭代,可以避免递归深度过深导致的栈溢出问题。

迭代法:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int n;
int diedai(int x){
	if(x <= 1) return 1;
	int a, b ;int temp;
	a = b  = 1;
	for(int i = 2 ; i <= x ;i++){
		temp = a + b;
		a = b ;
		b = temp;
	}
	return temp;
}
int main(){
	cin >> n;
	for(int i = 0 ; i < n ; i++){
		cout << diedai(i) << " ";
	}
} 

递归法:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int n;
int digui(int x){
	if(x <= 1){
		return 1;
	}
	return digui(x-1) + digui(x-2);
}
int main(){
	int n ;
	cin >> n;
	for(int i = 0 ; i < n ; i++){
		cout << digui(i) << " ";
	}
}

完全背包

题目

有N种物品和一个容量为C的背包,每 种物品都有无限件可用。第i种物品的容 量是c[i],价值是w[i]。求解将哪些物品 装入背包可使这些物品的容量总和不超过背包容量,且价值总和最大。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
int dp[maxn][maxn];
int a[maxn],w[maxn];
int n,c;
int main(){
	cin >> n >> c;
	for(int i = 1 ; i <= n ; i++){
		cin >> a[i] >> w[i];
	}
	for(int i = 1 ; i <= n ; i++){
		for(int j = a[i] ; j <= c ; j++){
			dp[i][j] = dp[i-1][j];
			dp[i][j] = max(dp[i][j],dp[i-1][j-a[i]] + w[i]);
		}
	}
	cout << dp[n][c];
}

多重背包

题目

有N种物品和一个容量为C的背包。
第i种物品最多有a[i]件可用,每件容量 是c[i],价值是w[i]。求解将哪些物品装 入背包可使这些物品的容量总和不超过背包容量,且价值总和最大。

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;
int t , m ,w,c;
int dp[maxn] ;
int main()
{
	cin >> t >> m ;
	for(int i = 1 ; i <= m ; i++)
	{
		cin >> w >> c ;
		for(int j = t ; j >= w ; j-- )
			dp[j]=max(dp[j],dp[j-w]+c);
	}
	cout << dp[t] << endl;
	return 0 ;
}

二维背包

题目

对于每件物品,具有两种不同的容量; 选择这件物品必须同时付出这两种代价; 对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得 到最大的价值。设这两种代价分别为代价1和代价2,第i件物品所需的两种代价 分别为a[i]和b[i]。两种代价可付出的最大值(两种背包容量)分别为V和U。物品 的价值为w[i]。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
struct node{
	int w;
	int b;
	int v;
}a[maxn];
int dp[maxn][maxn];
int n,c,d;
int main(){
	cin >> n ;
	for(int i = 1 ; i <= n ; i++){
		cin >> a[i].w >> a[i].b >> a[i].v;
	}
	cin >> c >> d;
	for(int i = 1 ; i <= n ; i++){
		for(int j = c ; j >= 0 ; j--){
			for(int k = d ; k >= 0 ; k--){
				if(j >= a[i].w && k >= a[i].b){
					dp[j][k] = max(dp[j][k],dp[j - a[i].w][k - a[i].b] + a[i].v);
				}
			}	
		}
	}
	cout << dp[c][d] << endl;
}



分组背包

题目:有N件物品和一个容量为C的背包。第i 件物品的容量是c[i],价值是w[i]。这些 物品被划分为若干组,每组中的物品最多选一件。求解将哪些物品装入背包可 使这些物品的容量总和不超过背包容量, 且价值总和最大。

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;
int n,m;
struct node {
	int w , v;
}group[maxn][maxn];
int a[maxn],dp[maxn];
int maxl = -INF;
int main(){
	cin >> m >> n;
	for(int i = 1; i <= n ; i++){
		int w , v , g;
		cin >> w >> v >> g;
		group[g][++a[g]].w = w;
		group[g][a[g]].v = v;
		maxl = max(maxl,g);
	}
	for(int i = 1 ; i <= maxl ; i++){
		if(a[i]){
			for(int j = m ; j >= 0 ; j--){
				for(int k = 1 ; k <= a[i]; k++){
					if(j >= group[i][k].w){
						dp[j] = max(dp[j],dp[j-group[i][k].w]+group[i][k].v);
					}
				}
			}
		}
	}
	cout << dp[m] << endl;
}
/*
45 3
10 10 1
10 5 1
50 400 2
out : 10
*/

快速幂

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;
ll Mode(ll a, ll b, ll mode)
{
	ll sum = 1;
	if(mode == 1)
		return 0 ;
	while (b) {
		if (b & 1) {
			sum = (sum * a) % mode;
			b--;
		}
		b /= 2;
		a = a * a % mode;
	}
	return sum;
}
int main()
{
	ll a,b,c ;
	cin >> a>> b >> c ;
	ll d ;
	d = Mode (a,b,c) ;
	printf("%lld^%lld mod %lld=%lld\n",a,b,c,d) ;
	return 0 ;
}
  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值