算法训练-Don't fear, DravDe is kind

#include<bits/stdc++.h>
using namespace std;
int n,dp[100001],v[100001],c[100001],l[100001],r[100001],maxx=0,ok[100001],ll,num=0,m=0;
vector<int> hash[100000];
//方法:使用一维数组,dp[a]表示有a且以a为结尾的最大值,那么a的前后数目都确定了,
//对于1<=k<a,判断l[k]+c[k]和l[a],来决定可不可以有k,同样r[k]!=c[a]+r[a];
//初始值:对于l[a]==0的都可以作为第一个,则return v[a]
//可以改用循环更快
int DP(int a){
    if(l[a]==0) return v[a];
    if(dp[a]!=0) return dp[a];
    for(vector<int>::iterator i=hash[l[a]].begin();i!=hash[l[a]].end();i++){
        if(*i>=a||r[*i]!=c[a]+r[a]) continue;//因为用了hash,可能*i>=a,本来会循环到a-1的,不会出现这种情况
        if(DP(*i)+v[a]>dp[a]){
            dp[a]=DP(*i)+v[a];
            ok[a]=*i;//前驱数组
        }
    }
    if(dp[a]>maxx&&r[a]==0){//r[a]==0才更新最优解,平常不限制最后一个r[a]==0,否则无法循环。都是0;
        maxx=dp[a];
        ll=a;//最优值的位置
    }
    return dp[a];
}
void show(int k){
    if(k==-1) return;
    m+=v[k];
    show(ok[k]);
    cout<<k<<" ";
}
int main() {
    cin>>n;
    memset(dp,0,sizeof(dp));
    memset(ok,255,sizeof(ok));
    for(int i=1;i<=n;i++){
        cin>>v[i]>>c[i]>>l[i]>>r[i];
        hash[c[i]+l[i]].push_back(i);
    }
    for(int i=1;i<=n;i++) DP(i);
    //保证得到最优解,其实只需循环r[i]==0的点就行了,
    //但是事实上,后面的都会用到前面的,因为我是递归,所以直接递归后面反而会变慢
    int p=ll;
    while(ll!=-1){
        ll=ok[ll];
        num++;
    }
    cout<<num<<endl;
    show(p);
    cout<<endl;
    cout<<maxx<<endl;
    return 0;
}

 

posted @ 2020-06-06 20:43  西伯利亚挖土豆  阅读(248)  评论(0编辑  收藏  举报