基础DP
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int DP[123][222];
int main(){
//01背包 递推1
//从第i个中挑选总重量不超过j的最大价值物品 dp[n][j]=0 dp[i][j] = max (dp[i+1][j],dp[i+1][j-wi]+vi) / dp[i+1][j]
//从前i个中挑选。。。。。。。。。。。。。 dp[0][j]=0 dp[i][j] = max (dp[i-1][j],dp[i-1][j-wi]+vi) / ..........
//dp[n]维memset
for(int i = n; i >= 1; i--){ //
for(int j = 0; j <= W; j++){
if(j-w[i] >= 0)
dp[i][j] = max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
else
dp[i][j] = dp[i+1][j];
}
}
cout << dp[1][W];
//dp[1]初始化
for(int i = 1; i <= n; i++){
for(int j = 0; j <= W; j++){
if(j-w[i] >= 0)
dp[i+1][j] = max(dp[i][j],dp[i][j-w[i]]+v[i]);
else
dp[i+1][j] = dp[i][j];
}
}
cout << dp[n+1][W];
//状态转移:从前i个中挑选总重量不超过j的最大价值物品转移到从前i+1中挑选...不超过j 和 不超过j+w[i]的状态
for(int i = 1; i <= n; i++){
for(int j = 0; j <= W; j++){
dp[i+1][j] = max(dp[i+1][j],dp[i][j]);
if(j+w[i] <= W){
dp[i+1][j+w[i]] = max(dp[i+1][j],dp[i+1][j+w[i]]+v[i]);
}
}
}
cout << dp[1][W];
//完全背包:前i个的取法:dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]]+v[i]) /dp[i-1][j]
for(int i = 1; i <= n; i++){
for(int j = 0; j <= W; j++){
if(j-w[i] >= 0)
dp[i+1][j] = max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
else
dp[i+1][j] = dp[i][j];
}
}
//一维DP的01背包:
for(int i = 1; i <= n; i++){
for(int j = W; j >= w[i]; j--){
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout << dp[W];
//一维DP的完全背包:
for(int i = 1; i <= n; i++){ //下标[1...n]
for(int j = w[i]; j <= W; j++){
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout << dp[W];
//O(nlogn)的LIS问题:
//dp 0x3f3f3f3f初始化
for(int i = 1;i <= n ;i++){
*lower_bound(dp+1,dp+n+1,a[i]) = a[i];
}
cout << lower_bound(dp+1,dp+n+1,INF)-(dp+1) << endl;
}
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
//int dp[]
int dfs(int cur,int W){
if(cur==n+1) return 0;
if(W<w[cur]) return dfs(cur+1,W);
return max(dfs(cur+1,W),dfs(cur+1,W-w[cur])+v[cur]);
}
int DP(int cur,int W){
if(cur==n+1) return dp[cur][W] = 0; //这里也要记忆
if(dp[cur][W]!=-1) return dp[cur][W];
if(W<w[cur]) return dp[cur][W] = DP(cur+1,W);
return dp[cur][W] = max(DP(cur+1,W),DP(cur+1,W-w[cur])+v[cur]);
}
int main(){
//input init->0
for(int i = 1; i <= n; i++){
for(int j = 0; j <= W; j++){ //向背包容量的状态转移
if(j-w[i] < 0) dp[i][j] = dp[i+1][j];
else dp[i][j] = max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
}
}
cout << dp[n][W] << endl;
}
int main(){
//input init->0
for(int i = 1; i <= n; i++){
for(int j = 0; j <= W; j++){ //压缩
if(j-w[i] < 0) dp[i&1][j] = dp[(i+1)&1][j];
else dp[i&1][j] = max(dp[(i+1)&1][j],dp[(i+1)&1][j-w[i]]+v[i]);
}
}
cout << dp[n&1][W] << endl;
}
int main(){
//init dp[0]=0
for(int i = 1; i <= n; i++){
for(int j = W; j >= w[i]; j--){
dp[j] = max(dp[j],dp[j-w[i]]+v[i]); //每次只需知道上面的和左上面的
}
}
cout << dp[W] << endl;
}
//ComPack
经典题目
https://people.cs.clemson.edu/~bcdean/dp_practice/
树形DP
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 1e3;
typedef vector<int> vi;
int level[maxn],parent[maxn];
vi G[maxn];
int sumC[maxn],sumS[maxn]; //孩子 孙子和
int dp[maxn];
int maxLevel;
//dp[i] = //d[i]表示以i为根的子树的最大独立集 di = max(sum of d son of i , 1+ sum of grandson of i)
void dfs(int u,int fa){ //更新level与parent
if(fa==-1)
level[u] = 0;
else
level[u] = level[fa]+1;
if(level[u] > maxLevel)
maxLevel = level[u];
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(v != fa) dfs(v,parent[v]=u);
}
}
int rootDP(int u){
parent[u] = -1;
maxLevel = -1;
dfs(u,p[u]); //建树
for(int i = maxLevel, i >= 0; i--){
for(int j = 0; j < V; j++){
if(level[j]==i){ // 一开始j是叶子节点
dp[j] = max(sumS[j]+1,sumC[j]);
if(i-1>=0) //刷表法
sumC[p[j]]+=dp[j];
if(i-2>=0)
sumS[p[p[j]]]+=dp[j];
}
}
}
return dp[u];
}
int main(){
int T,u,v; scanf("%d",&T);
while(T--){
int V; scanf("%d",&V);
for(int i = 0; i < V-1; i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int best = -1;
for(int i = 0; i < V; i++){
memset(sumC,0,sizeof sumC);
memset(sumS,0,sizeof sumS);
int temp = rootDP(i);
if(temp > best) best = temp;
}
printf("%d\n",best);
}
return 0;
}

浙公网安备 33010602011771号