1. 程式人生 > 其它 >CSUST 黃金礦工 題解(分組揹包+轉換dp方程狀態)

CSUST 黃金礦工 題解(分組揹包+轉換dp方程狀態)

題目連結

題目思路

算是兩個經典問題的結合

首先看到問題描述可以轉換為分組揹包

看到\(t\)很大,所以設\(dp[i]\)表示達到價值為\(i\)的最少時間是多少,然後\(dp\)即可

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define fi first
#define se second
#define debug printf("aaaaaaaaaaa\n");
const int maxn=2e2+100,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-7;
int n,sum;
int v[maxn],t[maxn],f[maxn];
int son[maxn],fa[maxn];
vector<pii> vec[maxn];
ll dp[10000+5];
int main(){
    int _; scanf("%d",&_);
    while(_--){
        scanf("%d%d",&n,&sum);
        for(int i=1;i<=n;i++){
            fa[i]=son[i]=0;
            vec[i].clear();
        }
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&v[i],&t[i],&f[i]);
            son[f[i]]=i;
            fa[i]=f[i];
        }
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(fa[i]!=0) continue;
            cnt++;
            int x=i;
            int tempv=0,tempt=0;
            while(x){
                tempv+=v[x];
                tempt+=t[x];
                vec[cnt].push_back({tempv,tempt});
                x=son[x];
            }
        }
        memset(dp,0x3f,sizeof(dp));
        dp[0]=0;
        for(int i=1;i<=cnt;i++){
            for(int j=10000;j>=0;j--){
                for(int k=0;k<vec[i].size();k++){
                    int x=vec[i][k].fi,y=vec[i][k].se;
                    if(j>=x){
                        dp[j]=min(dp[j],dp[j-x]+y);
                    }
                }
            }
        }
        for(int i=10000;i>=0;i--){
            if(dp[i]<=sum){
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}


卷也卷不過,躺又躺不平