- P1064 金明的预算方案
有依赖(分组)的背包问题,主件可以单独买,可以和一个附件,两个附件,依次判断即可
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std ;
const int N = 65 ;
const int M = 32010 ;
pair<int,int> a[N] ;
vector<pair<int,int>> b[N] ;
int f[M] ;
int main(){
int n , m ;
int p , v , w ;
scanf ("%d%d",&m,&n) ;
for (int i = 1 ; i <= n ; ++i){
scanf ("%d%d%d",&v,&w,&p) ;
w *= v ;
if (!p){ //若为主件
a[i] = {v,w} ;
}
else{
b[p].push_back({v,w}) ;
}
}
for (int i = 1 ; i <= n ; ++i){
if (!a[i].first) continue ; //若为附件
for (int j = m ; j >= 0 ; --j){
for (int k = 0 ; k < 1<<b[i].size() ; ++k){ //x个附件和主件的组合情况有2的x次方种
int x = a[i].first , y = a[i].second ; //主件的价钱和价值
for(int h = 0 ; h < b[i].size() ; ++h){
if (k >> h & 1){//每种组合都是互斥的,从中选出一种(这里是参考网上大佬的方法,有点玄学。。。。)
x += b[i][h].first ;
y += b[i][h].second ;
}
}
if (j >= x) f[j] = max(f[j] , f[j-x]+y) ;
}
}
}
printf ("%d\n",f[m]) ;
return 0 ;
}
- p1541 乌龟棋
#include <cstdio>
#include <algorithm>
using namespace std ;
const int N = 355 ;
const int M = 45 ;
int maze[N] , card[5] ;
int dp[M][M][M][M] ;
int main(){
int n , m ;
scanf ("%d%d",&n,&m) ;
for (int i = 1 ; i <= n ; ++i) scanf ("%d",&maze[i]) ;
for (int i = 1 ; i <= m ; ++i) {
int t ;
scanf ("%d",&t) ;
card[t] ++ ;
}
dp[0][0][0][0] = maze[1] ;
for (int a = 0 ; a <= card[1] ; ++a){
for (int b = 0 ; b <= card[2] ; ++b){
for (int c = 0 ; c <= card[3] ; ++c){
for (int d = 0 ; d <= card[4] ; ++d){
int score = maze[a + b*2 + c*3 + d*4 + 1] ; //是从1开始出发走到第几格为步数加初始格数(即1)
//要判断是否为0,否则会越界
if (a) dp[a][b][c][d] = max(dp[a][b][c][d],dp[a-1][b][c][d]+score) ;
if (b) dp[a][b][c][d] = max(dp[a][b][c][d],dp[a][b-1][c][d]+score) ;
if (c) dp[a][b][c][d] = max(dp[a][b][c][d],dp[a][b][c-1][d]+score) ;
if (d) dp[a][b][c][d] = max(dp[a][b][c][d],dp[a][b][c][d-1]+score) ;
}
}
}
}
printf ("%d\n",dp[card[1]][card[2]][card[3]][card[4]]) ;
return 0 ;
}
- p1063 能量项链
类似于环形石子的合并,只是最后的计算不同
#include <cstdio>
#include <algorithm>
using namespace std ;
const int N = 210 ;
int a[N] , f[N][N] ;
int main(){
int n ;
scanf("%d",&n) ;
for (int i = 1 ; i <= n ; i ++){
scanf ("%d",&a[i]) ;
a[i+n] = a[i] ;
f[i][i] = 0 ;
}
for (int len = 1 ; len < n ; ++len){
for (int i = 1 ; i <= 2*n-len ; ++i){
int j = i + len ;
f[i][j] = 0 ;
for (int k = i ; k < j ; ++ k){
f[i][j] = max(f[i][j] , f[i][k] + f[k+1][j] + a[i] * a[k+1] * a[j+1]) ;
}
}
}
int ans = 0 ;
for (int i = 1 ; i <= n ; ++ i)
ans = max(ans,f[i][i-1+n]) ;
printf ("%d\n",ans) ;
return 0 ;
}
- p1156垃圾陷阱
填或者是吃,感觉有种背包的味道,emmmm但是这个状态转移又有些难想,
f[i][j]表示当扔下第ii个垃圾时,高度为jj此时的还可以存活多久
对于转移,分两种情况:
当不选用这个垃圾来当垫子时:
f[i+1][j]=max(f[i+1][j],f[i][j]+num[i].f)f[i+1][j]=max(f[i+1][j],f[i][j]+num[i].f)
当选用这个垃圾来当垫子时
f[i+1][j+h[i]]=max(f[i+1][j+num[i].h],f[i][j])f[i+1][j+h[i]]=max(f[i+1][j+num[i].h],f[i][j])
在当前高度大于所求的高度时可以打印出时间并跳出
当爬不出时:
ans=max(ans,f[i][0])(1<=i<=n)
想法来自于下方大佬题解:
康康大佬的题解:https://www.luogu.org/blog/27-43wyy/solution-p1156
#include <cstdio>
#include <algorithm>
using namespace std ;
const int N = 110 ;
struct node{
int t , f , h ;
}p[N] ;
bool cmp(node a , node b){
return a.t < b.t ;
}
int f[N][N] ;
int main(){
int n , high ;
scanf ("%d%d",&high,&n) ;
for (int i = 1 ; i <= n ; ++ i) scanf("%d%d%d",&p[i].t,&p[i].f,&p[i].h) ;
sort(p+1,p+1+n,cmp) ;
f[0][0] = 10 ;
for (int i = 0 ; i < n ; ++ i){
for(int j = 0 ; j <= high ; ++ j){
if (f[i][j] >= p[i+1].t){
int h = j + p[i+1].h ;
if (h >= high){
printf ("%d\n",p[i+1].t) ;
return 0 ;
}
//当吃这个垃圾时
f[i+1][j] = max(f[i+1][j],f[i][j]+p[i+1].f) ;
//当用垃圾来当垫子时
f[i+1][h] = max(f[i+1][h],f[i][j]) ;
}
}
}
int ans = 0 ;
for (int i = 1 ; i <= n ;++ i)
ans = max(ans,f[i][0]) ;
printf ("%d\n",ans) ;
return 0 ;
}