#include<bits/stdc++.h>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =1e3+10;int f[N];intmain(){IOS;int n, m;cin >> n >> m;for(int i =0; i < n; i ++){int v, w;cin >> v >> w;for(int j = m; j >= v; j --)f[j]=max(f[j], f[j - v]+ w);}cout << f[m]<< endl;return0;}
AcWing 3. 完全背包問題
其實就是把01背包j循環層倒過來寫啊(
#include<bits/stdc++.h>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =1e3+10;int f[N];intmain(){IOS;int n, m;cin >> n >> m;for(int i =0; i < n; i ++){int v, w;cin >> v >> w;for(int j = v; j <= m; j ++)f[j]=max(f[j], f[j - v]+ w);}cout << f[m]<< endl;return0;}
AcWing 4. 多重背包問題
數據范圍非常小,暴力枚舉
#include<bits/stdc++.h>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =110;int f[N];intmain(){IOS;int n, m;cin >> n >> m;for(int i =0; i < n; i ++){int v, w, s;cin >> v >> w >> s;for(int j = m; j >= v; j --)for(int k =0; k <= s && k * v <= j; k ++)f[j]=max(f[j], f[j - k * v]+ k * w);}cout << f[m]<< endl;return0;}
AcWing 5. 多重背包問題 II
二進制表示法 : 把sss拆成log(s)log(s)log(s)份就可以表示出0 ~sss的所有的數,不再需要s份(s個1) 原來的復雜度是O(N?V?S)O(N * V * S)O(N?V?S),現在是O(N?V?log(S))O(N * V * log(S))O(N?V?log(S))
#include<bits/stdc++.h>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =2e3+10;structGood{int v, w;};int f[N];intmain(){IOS;int n, m;cin >> n >> m;vector<Good> goods;for(int i =0; i < n; i ++){int v, w, s;cin >> v >> w >> s;for(int k =1; k <= s; k *=2){goods.push_back({k * v, k * w});s -= k;}if(s >0) goods.push_back({s * v, s * w});}// 得到了我們需要的物品組 :goods,問題轉化為了01背包for(auto good : goods)for(int j = m; j >= good.v; j --)f[j]=max(f[j], f[j - good.v]+ good.w);cout << f[m]<< endl;return0;}
AcWing 9. 分組背包問題
/*for (int i = 0; i < n; i ++ )for (int j = m; j >= 0; j -- )f[j] = max(f[j], f[j - v[0]] + w[0], f[j - v[1]] + w[1], ..., f[j - v[s - 1]] + w[s - 1]);即 f[i][j] 表示只考慮前i組物品,體積至多為j的選法集合每個組內有s + 1種決策即 每個組內選1個(包含0個的情況)與其他組選出來的進行01背包*/#include<bits/stdc++.h>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =110;int v[N], w[N], f[N];intmain(){IOS;int n, m;cin >> n >> m;for(int i =0; i < n; i ++){int s;cin >> s;for(int j =0; j < s; j ++) cin >> v[j]>> w[j];for(int j = m; j >=0; j --)for(int k =0; k < s; k ++)if(j >= v[k])// 可以選這個f[j]=max(f[j], f[j - v[k]]+ w[k]);}cout << f[m]<< endl;return0;}
#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<vector>#include<unordered_map>#include<unordered_set>#include<set>#include<map>#include<stack>#include<queue>#include<deque>#include<ctime>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =1010;int a[N], f[N];intmain(){int n;cin >> n;for(int i =1; i <= n; i ++) cin >> a[i];for(int i =1; i <= n; i ++){f[i]=1;for(int j =1; j < i; j ++)if(a[j]< a[i])f[i]=max(f[i], f[j]+1);}int res =0;for(int i =1; i <= n; i ++) res =max(res, f[i]);cout << res << endl;return0;}
#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<vector>#include<unordered_map>#include<unordered_set>#include<set>#include<map>#include<stack>#include<queue>#include<deque>#include<ctime>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =1e5+10;int a[N], q[N];intmain(){int n;cin >> n;for(int i =0; i < n; i ++) cin >> a[i];int len =0;// 當前最大長度 / q中元素個數q[0]=-2e9;// 二分的邊界問題,為了保證數組中小于某個數的最大的數一定存在,q[0]是一個哨兵for(int i =0; i < n; i ++){int l =0, r = len;while(l < r){// 找比a[i]小的中最大的int mid = l + r +1>>1;if(q[mid]< a[i]) l = mid;else r = mid -1;}len =max(len, r +1);q[r +1]= a[i];}cout << len << endl;return0;}
#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<vector>#include<unordered_map>#include<unordered_set>#include<set>#include<map>#include<stack>#include<queue>#include<deque>#include<ctime>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =1010;char a[N], b[N];int f[N][N];intmain(){int n, m;cin >> n >> m >> a +1>> b +1;for(int i =1; i <= n; i ++)for(int j =1; j <= m; j ++){f[i][j]=max(f[i -1][j], f[i][j -1]);if(a[i]== b[j])f[i][j]=max(f[i][j], f[i -1][j -1]+1);}cout << f[n][m]<< endl;return0;}
#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<vector>#include<unordered_map>#include<unordered_set>#include<set>#include<map>#include<stack>#include<queue>#include<deque>#include<ctime>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =1010;char a[N], b[N];int f[N][N];intmain(){int n, m;cin >> n >> a +1>> m >> b +1;for(int i =0; i <= n; i ++) f[i][0]= i;for(int i =0; i <= m; i ++) f[0][i]= i;for(int i =1; i <= n; i ++)for(int j =1; j <= m; j ++){f[i][j]=min(f[i -1][j], f[i][j -1])+1;if(a[i]== b[j]) f[i][j]=min(f[i][j], f[i -1][j -1]);else f[i][j]=min(f[i][j], f[i -1][j -1]+1);}cout << f[n][m]<< endl;return0;}
AcWing 899. 編輯距離
注意頭文件。
#include<iostream>#include<algorithm>#include<cstring>#include<string>#include<cmath>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =15, M =1010;char str[M][N];int f[N][N];intedit_distance(char a[],char b[]){int lena =strlen(a +1), lenb =strlen(b +1);for(int i =0; i <= lena; i ++) f[i][0]= i;for(int i =0; i <= lenb; i ++) f[0][i]= i;for(int i =1; i <= lena; i ++)for(int j =1; j <= lenb; j ++){f[i][j]=min(f[i -1][j], f[i][j -1])+1;if(a[i]== b[j]) f[i][j]=min(f[i][j], f[i -1][j -1]);else f[i][j]=min(f[i][j], f[i -1][j -1]+1);}return f[lena][lenb];}intmain(){int n, m;cin >> n >> m;for(int i =0; i < n; i ++) cin >> str[i]+1;while(m --){char s[N];int limit;cin >> s +1>> limit;int res =0;for(int i =0; i < n; i ++)if(edit_distance(s, str[i])<= limit) res ++;cout << res << endl;}return0;}
#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<vector>#include<unordered_map>#include<unordered_set>#include<set>#include<map>#include<stack>#include<queue>#include<deque>#include<ctime>#include<sstream>#defineendl'\n'#defineIOSios::sync_with_stdio(false); cin.tie(0); cout.tie(0)#definelowbit(x)(x&-x)usingnamespace std;constdouble pi =acos(-1);typedeflonglong ll;typedef pair<int,int> PII;typedef pair<long,long> PLL;constint N =310;int w[N];int f[N][N];intmain(){int n;cin >> n;for(int i =1; i <= n; i ++) cin >> w[i], w[i]+= w[i -1];for(int len =2; len <= n; len ++){for(int i =1; i + len -1<= n; i ++){int j = i + len -1;f[i][j]=2e9;for(int k = i +1; k <= j; k ++){f[i][j]=min(f[i][j], f[i][k -1]+ f[k][j]+ w[j]- w[i -1]);}}}cout << f[1][n]<< endl;return0;}
#include<iostream>#include<cstring>usingnamespace std;constint N =20, M =1<< N;int n;int f[M][N];int w[N][N];intmain(){cin >> n;for(int i =0; i < n; i ++)for(int j =0; j < n; j ++)cin >> w[i][j];memset(f,0x3f,sizeof f);f[1][0]=0;for(int i =0; i <1<< n; i ++)for(int j =0; j < n; j ++)if(i >> j &1)for(int k =0; k < n; k ++)if(i -(1<< j)>> k &1)f[i][j]=min(f[i][j], f[i -(1<< j)][k]+ w[k][j]);cout << f[(1<< n)-1][n -1]<< endl;//位運算的優先級低于'+'-'所以有必要的情況下要打括號return0;}
樹形DP
AcWing 285. 沒有上司的舞會
翻譯 :選了某個節點就不能選擇它的父節點和子節點,求最大權值和。
#include<iostream>#include<cstring>usingnamespace std;constint N =6010;int n;int e[N], ne[N], h[N], idx;int w[N];int f[N][2];bool st[N];// 是否有父節點voidadd(int a,int b){e[idx]= b, ne[idx]= h[a], h[a]= idx ++;}voiddfs(int u){// f[u][0] = 0;f[u][1]= w[u];for(int i = h[u];~i; i = ne[i])// ~i == i != -1{int j = e[i];dfs(j);// 兩種情況都是 +=f[u][1]+= f[j][0];f[u][0]+=max(f[j][1], f[j][0]);}}intmain(){cin >> n;for(int i =1; i <= n; i ++) cin >> w[i];memset(h,-1,sizeof h);// 不初始化圖見祖宗for(int i =1; i <= n -1; i ++){int a, b;cin >> a >> b;add(b, a);st[a]=true;}int root =1;while(st[root])++ root;dfs(root);cout <<max(f[root][0], f[root][1])<< endl;return0;}
記憶化搜索
AcWing 901. 滑雪
f[i,j]f[i,j]f[i,j]表示所有從(i,j)(i,j)(i,j)開始滑的路徑
#include<iostream>#include<cstring>usingnamespace std;constint N =310;int n, m;int h[N][N];int f[N][N];int dx[4]={1,0,-1,0}, dy[4]={0,1,0,-1};intdp(int x,int y){int&v = f[x][y];// 使用"&",相當于下面每次用到v其實可以換成f[x][y]if(v !=-1)return v;// 記憶化搜索v =1;for(int i =0; i <4; i ++){int a = x + dx[i], b = y + dy[i];if(a >=0&& a < n && b >=0&& b < m && h[a][b]< h[x][y])v =max(v,dp(a, b)+1);}return v;}intmain(){cin >> n >> m;for(int i =0; i < n; i ++)for(int j =0; j < m; j ++)cin >> h[i][j];memset(f,-1,sizeof f);int res =0;for(int i =0; i < n; i ++)for(int j =0; j < m; j ++)res =max(res,dp(i, j));cout << res << endl;return0;}