int cnt = 0; for (int i = 1; i <= n; i ++ ) { int a, b, s; cin >> a >> b >> s; int k = 1; while (k <= s) { cnt ++ ; v[cnt] = a * k; w[cnt] = b * k; s -= k; k *= 2; } if (s > 0) { cnt ++ ; v[cnt] = a * s; w[cnt] = b * s; } }//二进制优化操作
n = cnt;
for (int i = 1; i <= n; i ++ ) for (int j = m; j >= v[i]; j -- ) f[j] = max(f[j], f[j - v[i]] + w[i]);
cout << f[m] << endl;
return0; }
分组背包问题
有 n 组物品,m 的体积,每组物品只能选择一个 状态转移方程:f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
intmain() { scanf("%d", &n); for (int i = 1; i <= n; i ++ )scanf("%d",&a[i]); for (int i = 1; i <= n; i ++ ){ f[i]=1;//只有a[i]一个数 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]); printf("%d\n",res); return0; }
intmain() { scanf("%d", &n); for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
int len = 0; for (int i = 0; i < n; i ++ ) { int l = 0, r = len; while (l < r) { 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];//替换或添加 }
for (int i = 0; i <= m; i ++ )f[0][i]=i; for (int i = 0; i <= n; i ++ )f[i][0]=i;//初始化字符串的编辑操作 for (int i = 1; i <= n; i ++ ){ for (int j = 1; j <= m; j ++ ){ f[i][j]=min(f[i-1][j]+1,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);//状态转移方程 } } printf("%d\n",f[n][m]); return0; }
int n; int s[N]; int f[N][N];//状态表示:集合f[l][r]为[l,r]区间;属性:所堆成的最小值 intmain() { scanf("%d", &n); for (int i = 1; i <= n; i ++ )scanf("%d",&s[i]); for (int i = 1; i <= n; i ++ )s[i]+=s[i-1];//前缀和用来求一段区间的和
for (int len = 2; len <= n; len ++ )//区间长度为len//枚举长度 for (int i = 1; i+len-1 <= n; i ++ ){//意思就是i在区间[1,n-len+1]中去//枚举区间 int l=i,r=i+len-1;//区间在[i,i+len-1]中间长度为len//设置l和r的区间 f[l][r]=1e9;//初始化最大值 for (int k = l; k < r; k ++ )//枚举分界点//不取r f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);//找到最小值状态转移方程为f[l][k]+f[k+1][r]+s[r]-s[l-1]; } printf("%d\n",f[1][n]);//输出区间[1,n]的最小值 return0; }
int n; int w[N];//每个节点的高兴度 int h[N], e[N], ne[N], idx;//邻接表存储树
bool st[N];//判断是否有父节点 int f[N][2];
voidadd(int a, int b)// 添加一条边a->b { e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ; } voiddfs(int u){ f[u][0]=0; f[u][1]=w[u];//初始化f[u][1],当第二维是0则不选该点即高兴度为0,同理f[u][1]=w[u]; for (int i = h[u]; i!=-1 ; i =ne[i] ){//遍历u的子节点进行深度优先遍历 int j=e[i]; dfs(j); //状态转移方程 f[u][0]+=max(f[j][0],f[j][1]);//f[u][0]表示不选择父节点u,所以在f[j][0]和f[j][1]取最大值 f[u][1]+=f[j][0];//f[u][1]表示选择根节点u,所以累加不选择子节点的f[j][0] } }
intmain() { cin>>n; for (int i = 1; i <= n; i ++ )cin>>w[i]; memset(h, -1, sizeof h); for (int i = 0; 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);//dfs对f[i][j]进行状态转移计算 cout<<max(f[root][0],f[root][1])<<endl;//取选与不选根节点的最大值 return0; }
intdp(int x,int y){ int &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>=1&&a<=n&&b>=1&&b<=m&&h[a][b]<h[x][y])//判断是否越界且上一个经过的点的高度是否大于当前高度 v=max(v,dp(a,b)+1); } return v; }
intmain() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) scanf("%d", &h[i][j]); memset(f, -1, sizeof f); int res=0; for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) res=max(res,dp(i,j)); printf("%d\n",res); return0; }