这学期大致涉及到的都在这了,缺少的发在评论吧 ,有时间会补上。
递归和分治
合并排序
#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≤ p ≤ n)为参数,实现如下功能:将序列a 的p个数与后n – p个数对调,且不改变这p 个数(或n– p 个数)之间的相对位置。例如,长度为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 ;
}