一.dp-bag
(一).01bag
1.求最值
(1).二维版本
#include <iostream> using namespace std; int a[1010][1010]; int v,w; int main() { int n, m; cin >> n >> m; for(int i = 1; i <= n; i++){ cin>>v>>w; for(int j = 1; j <= m; j++) { if(j<v) a[i][j] = a[i - 1][j]; if(j>=v) a[i][j] = max(a[i-1][j], a[i - 1][j - v] + w); } } cout << a[n][m] << endl; return 0; }
(2).一维版本
#include <iostream> using namespace std; int a[1010],n,m,v,w; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>v>>w; for(int j=m;j>=v;j--){ a[j]=max(a[j],a[j-v]+w); } } cout<<a[m]; return 0; }
2.求方案数
(1).二维版本
#include <iostream> using namespace std; int n,m,v; int a[110][10010]; int main(){ cin>>n>>m; a[0][0]=1; for(int i=1;i<=n;i++){ cin>>v; for(int j=0;j<=m;j++){ if(j<v) a[i][j]=a[i-1][j]; else a[i][j]=a[i-1][j]+a[i-1][j-v]; } } cout<<a[n][m]; return 0; }
(2).一维版本
#include <iostream> using namespace std; int a[10005],n,m,v; int main(){ cin>>n>>m; a[0]=1; for(int i=1;i<=n;i++){ cin>>v; for(int j=m;j>=v;j--){ a[j]+=a[j-v]; } } cout<<a[m]; return 0; }
(二).完全背包
1.二维版:
优化的原理就是: dp[i][j - v] = max(dp[i - 1][j - v], dp[i - 1][j - 2 * v] + w, dp[i - 1][j - 3 * v] + 2 * w, .....); 而我们需要的dp[i][j]的状态表示是: dp[i][j]= max(dp[i - 1][j], dp[i - 1][j - v] + w, dp[i - 1][j - 2 * v] + 2 * w, dp[i - 1][j - 3 * v] + 3 * w); 将每一项一一比对,我们可以得到下列状态表示: dp[i][j] = max(dp[i - 1][j], dp[i][j - v] +w); 这里采用的方法是取并集 #include <iostream> using namespace std; int N,V; int a[1010][1010]; int main(){ cin>>N>>V; int v,w; for(int i=1;i<=N;i++){ cin>>v>>w; for(int j=1;j<=V;j++){ if(j<v) a[i][j]=a[i-1][j]; if(j>=v) a[i][j]=max(a[i-1][j],a[i][j-v]+w); } } cout<<a[N][V]; return 0; }
2.一维版:
#include <iostream> using namespace std; int N,V; int a[1010]; int main(){ cin>>N>>V; int v,w; for(int i=1;i<=N;i++){ cin>>v>>w; for(int j=v;j<=V;j++){ a[j]=max(a[j],a[j-v]+w); } } cout<<a[V]; return 0; } //完全背包的题型也有另外一种,要求方案数量,这里没有给出
(三).多重背包
1.二维通俗版本:
#include <iostream> using namespace std; int a[110][110]; int v,w,n,m,s; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>v>>w>>s; for(int j=1;j<=m;j++){ for(int k=0;k*v<=j && k<=s;k++){ a[i][j]=max(a[i][j],a[i-1][j-k*v]+k*w); } } } cout<<a[n][m]; return 0; }
2.一维二进制优化
#include <iostream> using namespace std; int n,m,s,v,w,a[2000010],b[2000010],t=1; int dp[2010]; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>v>>w>>s; for(int j=1;j<=s;j<<=1){ a[t]=j*v;b[t++]=j*w; s-=j; } if(s>0){ a[t]=s*v;b[t++]=w*s; } }t--; for(int i=1;i<=t;i++){ for(int j=m;j>=a[i];j--){ dp[j]=max(dp[j],dp[j-a[i]]+b[i]); } } cout<<dp[m]; return 0; }
#include <iostream> using namespace std; const int N = 2010; int n,m; int f[N]; int main () { cin >> n >> m; for (int i = 1;i <= n;i++) { int w,v,s; cin >> w >> v >> s; for (int k = 1;k <= s;k <<= 1) { for (int j = m;j >= w * k;j--) f[j] = max (f[j],f[j - w * k] + v * k); s -= k; } if (s) { for (int j = m;j >= w * s;j--) f[j] = max (f[j],f[j - w * s] + v * s); } } cout << f[m] << endl; return 0; }
(四).多维01背包
三维版本:
#include <iostream> using namespace std; int N, V, M; int v,m,w,a[110][110]; int main () { cin >> N >> V >> M; for (int i = 1; i <= N; i ++){ cin>>v>>m>>w; for (int j = V; j >= v; j --) for (int k = M; k >= m; k --) a[j][k] = max (a[j][k],a[j - v][k - m ]+w); } cout << a[V][M]; }
(五).分组0-1背包
二维:
#include <iostream> using namespace std; int a[110][110]; int v[110][110],w[110][110],s[110]; int n,m,k; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>s[i]; for(int j=1;j<=s[i];j++){ cin>>v[i][j]>>w[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ a[i][j]=a[i-1][j]; for(int k=1;k<=s[i];k++){ if(j>=v[i][k]) a[i][j]=max(a[i][j],a[i-1][j-v[i][k]]+w[i][k]); } } } cout<<a[n][m]<<endl; }
一维:
#include <iostream> using namespace std; int v[105],w[105],a[105],n,m,s; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>s; for(int j=1;j<=s;j++) cin>>v[j]>>w[j]; for(int j=m;j>=1;j--) for(int k=1;k<=s;k++) if(j>=v[k]) a[j]=max(a[j],a[j-v[k]]+w[k]); } cout<<a[m]; return 0; }
(六).0-1背包问题求方案数
#include <iostream> using namespace std; int n,m,v,w; int a[1010],b[1010]; int main(){ cin>>n>>m; for(int i=0;i<=m;i++) a[i]=1; for(int i=1;i<=n;i++){ cin>>v>>w; for(int j=m;j>=v;j--){ if(b[j]<b[j-v]+w) a[j]=a[j-v],b[j]=b[j-v]+w; else if(b[j]==b[j-v]+w) (a[j]+=a[j-v])%=1000000007; } } cout<<a[m]; return 0; }
(七).0-1背包问题求具体方案
二维
#include <iostream> using namespace std; int n,m; int w[1010],v[1010]; int f[1010][1010]; int main () { cin >> n >> m; for (int i = 1;i <= n;i++) cin >> w[i] >> v[i]; for (int i = n;i >= 1;i--) { for (int j = 0;j <= m;j++) { f[i][j] = f[i + 1][j]; if (j >= w[i]) f[i][j] = max (f[i][j],f[i + 1][j - w[i]] + v[i]); } } for (int i = 1,j = m;i <= n;i++) { if (j >= w[i] && f[i][j] == f[i + 1][j - w[i]] + v[i]) { cout << i << ' '; j -= w[i]; } } return 0; }
一维
#include<iostream> #include<vector> using namespace std; const int N=1001; int v[N],w[N],n,V,f[N]; vector<int> ans[N]; int main() { cin>>n>>V; for(int i=1;i<=n;i++) scanf("%d %d",&v[i],&w[i]); for(int i=1;i<=n;i++) for(int j=V;j>=v[i];j--) { if(f[j]<f[j-v[i]]+w[i]) { ans[j]=ans[j-v[i]]; //复制方案 ans[j].push_back(i); //更新方案 f[j]=f[j-v[i]]+w[i]; } else if(f[j]==f[j-v[i]]+w[i]) { vector<int> b=ans[j-v[i]];b.push_back(i); if(b<ans[j]) ans[j]=b; //更新方案 } } for(int i=0;i<ans[V].size();i++) //输出方案 cout<<ans[V][i]<<' '; return 0; }
二.数论
(一).求最大公约数--辗转相除法
int gcd(int a,int b){ if(b==0) return a; else return gcd(b,a%b); }
(二).求最小公倍数
num=(a*b)/gcd(a,b);
(三).质数判断
#质数是指大于1的自然数中除了1与本身没有其他因数的数字 bool prime(int n){ for(int i=2;i*i<=n;i++){ if(n%i==0) return false; } return true; }
三.图论
(一).DFS
#include <iostream> #include <vector> using namespace std; int n; int book[10]; vector< int > path; void dfs(){ if(path.size()==n){ vector<int>::iterator h=path.begin(); while(h!=path.end()){ cout<<" "<<*h; h++; }cout<<endl; } for(int i=1;i<=n;i++){ if(book[i]==1) continue; path.push_back(i); book[i]=1; dfs(); path.pop_back(); book[i]=0; } } int main(){ cin>>n; dfs(); return 0; }
(二).BFS
#include <iostream> #include <vector> #include <queue> using namespace std; struct node{ int x,y,s; }; int n,m,dx,dy,sx,sy,nx,ny; char ch; int a[300][300],dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; queue<node> q; node t,k; int bfs(){ q.push({sx,sy,0});a[sx][sy]=-1; while(!q.empty()){ t=q.front(); q.pop(); if(t.x==dx && t.y==dy) return t.s; for(int i=0;i<4;i++){ nx=t.x+dir[i][0]; ny=t.y+dir[i][1]; if( nx<1 || nx>n || ny<1 ||ny>m ||a[nx][ny]==-1) continue; q.push({nx,ny,t.s+1}); a[nx][ny]=-1; } } return -1; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>ch; if(ch=='*') a[i][j]=10,dx=i,dy=j; else if(ch=='@') a[i][j]=1,sx=i,sy=j; else if(ch=='.') a[i][j]=0; else if(ch=='#') a[i][j]=-1; } } cout<<bfs(); return 0; }
四.排序
(一).快速排序
void quick_sort(int q[], int l, int r) { if (l >= r) return; int i = l - 1, j = r + 1, x = q[l + r >> 1]; while (i < j) { do i ++ ; while (q[i] < x); do j -- ; while (q[j] > x); if (i < j) swap(q[i], q[j]); } quick_sort(q, l, j), quick_sort(q, j + 1, r); }
(二).冒泡
#include <iostream> using namespace std; int a[7]={0,3,7,6,5,2,1}; int main(){ for(int i=1;i<=6;i++){ for(int j=1;j<=6-i;j++){ if(a[j]>a[j+1]){ int temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } } for(int i=0;i<=6;i++) cout<<a[i]<<" "; return 0; }
五.基础算法
1.前缀和
#include <iostream> using namespace std; int a[100],n; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=2;i<=n;i++){ a[i]+=a[i-1]; } return 0; }
2.二分查找
int BinarySearch(int nums[],int target) { int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + ((right - left)/2); if (nums[mid] == target) return mid; else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } return -1; }
六.dp_else
(一).线性dp
1.最长公共子序列
例题:
输入n=4,m=4,s=“abcd",t="becd", 输出3("bcd")
#include <iostream> using namespace std; char a[1005],b[1005]; int f[1005][1005],n,m; int main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int j=1;j<=m;j++) cin>>b[j]; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1; else f[i][j]=max(f[i-1][j],f[i][j-1]); } } cout<<f[n][m]; return 0; }
2.最长上升子序列
例题:
4 2 3 1 5 =>2 3 5
#include <iostream> using namespace std; int a[1005],b[1005]; int n,Max=-10000; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int j=1;j<=n;j++){ b[j]=1; for(int i=1;i<j;i++){ if(a[i]<a[j]){ b[j]=max(b[j],b[i]+1); } } } for(int i=1;i<=n;i++){ if(b[i]>Max) Max=b[i]; } cout<<Max; return 0; }
3.最大子段和(luogu P1115)
#include <iostream> using namespace std; int n,a[200010],b[200010],Max=-100000; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) b[i]=max(b[i-1]+a[i],a[i]); for(int i=1;i<=n;i++){ if(b[i]>Max) Max=b[i]; } cout<<Max; return 0; }
Else.
1.sort的用法
1.数组排序 //sort函数第三个参数采用默认从小到大 int a[]={45,12,34,77,90,11,2,4,5,55}; sort(a,a+10);
//sort函数第三个参数自己定义,实现从大到小 int a[]={45,12,34,77,90,11,2,4,5,55}; sort(a,a+10,cmp); //自定义函数 bool cmp(int a,int b){ return a>b; }
//结构体排序一定要自定义函数 1 #include<iostream> 2 #include<algorithm> 3 #include"cstring" 4 using namespace std; 5 typedef struct student{ 6 char name[20]; 7 int math; 8 int english; 9 }Student; 10 bool cmp(Student a,Student b); 11 main(){ 12 //先按math从小到大排序,math相等,按english从大到小排序 13 Student a[4]={{"apple",67,89},{"limei",90,56},{"apple",90,99}}; 14 sort(a,a+3,cmp); 15 for(int i=0;i<3;i++) 16 cout<<a[i].name <<" "<<a[i].math <<" "<<a[i].english <<endl; 17 } 18 bool cmp(Student a,Student b){ 19 if(a.math >b.math ) 20 return a.math <b.math ;//按math从小到大排序 21 else if(a.math ==b.math ) 22 return a.english>b.english ; //math相等,按endlish从大到小排序23 24 }
//容器sort很方便 sort(v1.begin(),v1.end());//升序第三个参数可以默认,也可以使用less<int>() sort(v2.begin(),v2.end(),greater<int>());//降序