健身

健身

https://www.nowcoder.com/questionTerminal/7f080ec10f4e46c2bd13ea8b565273d0

链接:https://www.nowcoder.com/questionTerminal/7f080ec10f4e46c2bd13ea8b565273d0
来源:牛客网
因为公司有免费健身福利,快手程序员老铁们都很爱健身,而且他们健身时像工作一样充满效率。
他们把健身过程神奇的简化了出来:健身有N种锻炼方式可选,器材可看成在一条直线上。
每种锻炼方式距门口Xi米,因为有的器材上可以支持多种锻炼方式,因此有可能出现两种锻炼方式的距离是一样的,即Xa = Xb。

老铁们一进健身房门口就开启健身形态,每走1米,就能获得1点锻炼效果值,而每种锻炼方式也有Ei的效果值,锻炼的过程就是从门口走到某种锻炼方式锻炼,然后到下一个方式锻炼,最后返回门口的过程。需要注意的是,锻炼过程中老铁们不会为了获得效果而刻意走回头路。

老铁们很想知道如果想选择某几种锻炼方式,怎样获得最大锻炼效果。

输入描述:
第一行N,表示锻炼方式的个数
第二行N个整数,表示每种锻炼方式距门口的距离
第三行N个整数,表示每种锻炼方式的效果值
输出描述:
N个整数,第k行表示选择k种锻炼方式时获得的最大锻炼效果
示例1

输入

5
1 2 3 4 5
1 1 1 1 1

输出

11
12
13
14
15

说明

对于样例第一行,老铁选择去第5种锻炼方式,考虑来回路程,一共获得5+1+5点锻炼效果值

备注:
对于所有数据,N <= 100,000,输出结果在32位整数范围内

解析:

首先,这道题的测试数据的确不合理。
具体可以参考由Bugboy 提供的测试用例:
5
1 4 5 6 7
10 2 9 1 1
输出为:
19
29
34
36
37
下面看菜鸡如何一步一步地优化😂。
1.dfs暴力,首先想到的办法就是暴力,在每一个器材上,只有两种选择——选择该器材或者不选择该器材,代码很简单,具体细节可以参见代码。当输入长度为n时,时间复杂度为O(2n),最终通过20%。
#include <iostream>
#include <algorithm>
using  namespace std;
const int maxn=100005;
int book[maxn];
struct node {
    int dis;
    int value;
};
node vec[maxn];
int n;
void dfs(int start,int value,int  num, int max_dis){
    if (start>n){
        return;
    }

    if(book[num]<max_dis*2+value){
        book[num]=max_dis*2+value;
    }
    dfs(start+1,value+vec[start].value,num+1,max(max_dis,vec[start].dis));
    dfs(start+1,value,num,max_dis);
    return;
}
int main(){
    cin>>n;
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].dis;
    }
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].value;
    }
    dfs(0,0,0,0);
    for (int i = 1; i <=n ; ++i) {
        cout<<book[i]<<endl;
    }
    return 0;
}
2.暴力不行,我就想到了动态规划。先按照距离升序对器材进行排序,保证后面的器材比前面的器材距离大。然后就是动态规划,matrix[i][j]表示前i个器材中选择j个,并且i必选时的最大能量。matrix[i][j]应该等于前i-1个器材中选择j-1个器材的最大效果值,然后再加上第i个器材效果和2倍的第i个器材的距离。那么递推公式为:
matrix[i][j]=max0<=k<=i-1{matrix[k][j-1]+valuei+disi*2-valuek}
其中valuei,disi表示第i个效果值和距离。
具体代码如下,当输入长度为n时,时间复杂度为O(n3),最终通过40%。
#include <iostream>
#include <algorithm>
using  namespace std;
const int maxn=100005;
int book[maxn];
struct node {
    int dis;
    int value;
    int total;
};
node vec[maxn];
int n;
int cmp(node a ,node b){
    return a.dis<b.dis;
}
int matrix[maxn][maxn];
int main(){
    cin>>n;
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].dis;
    }
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].value;
        vec[i].total=vec[i].dis*2+vec[i].value;
    }
    sort(vec,vec+n,cmp);
    matrix[1][1]=vec[0].dis*2+vec[0].value;
    for (int i = 1; i <=n ; ++i) {
        for (int j = 1; j <=i ; ++j) {
            for (int k = 1; k <=i-1 ; ++k) {
                if(matrix[i][j]<matrix[k][j-1]+vec[i-1].value+vec[i-1].dis*2-(matrix[k][j-1]>0?vec[k-1].dis*2:0)){
                    matrix[i][j]=matrix[k][j-1]+vec[i-1].value+vec[i-1].dis*2-(matrix[k][j-1]>0?vec[k-1].dis*2:0);
                }
            }
        }
    }
    for (int i = 1; i <=n ; ++i) {
        int max_v=0;
        for (int j = i; j <=n ; ++j) {
            if (max_v<matrix[j][i]){
                max_v=matrix[j][i];
            }
        }
        cout<<max_v<<endl;
    }
    return 0;
}
3.贪心,这个很明显具有最优子结构的性质,也具有贪心选择性。每一次选择都选择效果值增加最多的那个器材。当输入长度为n时,需要做n次选择,每一次选择需要花费O(n)的时间,所以总的时间复杂度为O(n2),最终通过60%。
#include <iostream>
#include <queue>
#include <vector>
#include <string.h>
#include <string>
#include <algorithm>
using  namespace std;
const int maxn=100005;
int book[maxn];
struct node {
    int dis;
    int value;
    int total;
};
node vec[maxn];
int n;
int main(){
    cin>>n;
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].dis;
    }
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].value;
        vec[i].total=vec[i].dis*2+vec[i].value;
        book[i]=0;
    }
    int j=0,index=0;
    while (j<n){
        for (int i = 0; i <n ; ++i) {
            if(vec[index].total<vec[i].total)index=i;
        }
        book[j+1]=book[j]+vec[index].total;
        for (int i = 0; i < n; ++i) {
            if(i==index) continue;
            if(vec[index].dis>=vec[i].dis){
                vec[i].dis=0;
                vec[i].total=vec[i].value;
            } else{
                vec[i].dis=vec[i].dis-vec[index].dis;
                vec[i].total=vec[i].dis*2+vec[i].value;
            }
        }
        vec[index].value=0;
        vec[index].total=0;
        vec[index].dis=0;
        j++;
    }

    for (int i = 1; i <=n ; ++i) {
        cout<<book[i]<<endl;
    }
    return 0;
}

4.贪心的优化。上面的贪心算法中,每一次选择需要花费太长的时间,可以进一步地优化。我们需要认识到每一次选择的器材有一个特点,就是每一次选择的器材是剩下的器材中,效果值value最大的或者是距离dis最大的。所以可以使用两个优先队列来完成每一次选择器材。当输入长度为n时,时间复杂度为O(nlogn),最终通过100%。
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using  namespace std;
const int maxn=100005;
int book[maxn];
int record[maxn];
struct node {
    int index;
    int dis;
    int value;
    int total;
};

struct cmp1{
    bool operator()(node a,node b){
        return a.value<b.value;
    }
};
struct  cmp2{
    bool operator()(node a ,node b){
        return a.total<b.total;
    }
};
node vec[maxn];
int n;

priority_queue <node,vector<node>,cmp1> q_max_value;
priority_queue <node,vector<node>,cmp2> q_max_total;
int main(){
    cin>>n;
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].dis;
    }
    for (int i = 0; i <n ; ++i) {
        cin>>vec[i].value;
        vec[i].index=i;
        vec[i].total=vec[i].dis*2+vec[i].value;
        q_max_total.push(vec[i]);q_max_value.push(vec[i]);
    }
    int j=0,last_dis=0;
    node t_max_total,t_max_v;
    while (j<n){
        if (!q_max_total.empty()){
            t_max_total=q_max_total.top();
            q_max_total.pop();
            while (record[t_max_total.index]!=0&&(!q_max_total.empty())){
                t_max_total=q_max_total.top();
                q_max_total.pop();
            }
        }
        if (!q_max_value.empty()){
            t_max_v=q_max_value.top();
            q_max_value.pop();
            while (record[t_max_v.index]!=0&&(!q_max_value.empty())){
                t_max_v=q_max_value.top();
                q_max_value.pop();
            }
        }
        if(t_max_total.total-(t_max_total.dis>last_dis?2*last_dis:2*t_max_total.dis)>t_max_v.total-(t_max_v.dis>last_dis?2*last_dis:2*t_max_v.dis)){
            book[j+1]=book[j]+t_max_total.total-(t_max_total.dis>last_dis?2*last_dis:2*t_max_total.dis);
            last_dis=max(t_max_total.dis,last_dis);
            record[t_max_total.index]=1;
            q_max_value.push(t_max_v);
        } else {
            book[j+1]=book[j]+t_max_v.total-(t_max_v.dis>last_dis?2*last_dis:2*t_max_v.dis);
            last_dis=max(t_max_v.dis,last_dis);
            record[t_max_v.index]=1;
            q_max_total.push(t_max_total);
        }
        j++;
    }
    for (int i = 1; i <=n ; ++i) cout<<book[i]<<endl;
    return 0;
}

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务