1. 程式人生 > 其它 >【快手筆試題】程式設計題-健身

【快手筆試題】程式設計題-健身

技術標籤:演算法

[程式設計題]健身

因為公司有免費健身福利,快手程式設計師老鐵們都很愛健身,而且他們健身時像工作一樣充滿效率。
他們把健身過程神奇的簡化了出來:健身有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位整數範圍內

思路:

e i ei ei是能量, d i s t dist dist是距離
要求解 m a x ( e 1 + e 2 + e 3 + … + e n ) + m a x ( d i s t ∗ 2 ) max(e1+e2+e3+…+en)+max(dist*2)

max(e1+e2+e3++en)+max(dist2)
d i s t dist dist e 1 e1 e1有關,
即求解 m a x ( e 1 , e 2 , e 3 + e n − 1 ) + m a x ( e n ) + m a x ( d i s t ∗ 2 ) max(e1,e2,e3+en-1)+max(en)+max(dist*2) max(e1,e2,e3+en1)+max(en)+max(dist2)
此時可看出,前n-1個一定是val的最大值,而 m a x ( e n ) + m a x ( d i s t ∗ 2 ) max(en)+max(dist*2)
max(en)+max(dist2)
可以看到要麼是
1. e n + d i s t ∗ 2 en+dist*2 en+dist2的和的值最大,否則
2. v a l val val最大, d i s t dist dist是前面的某個n的值。
所以應該找出前 k − 1 個 k-1個 k1最大的E,剩下的如果器材A的 d d d比前面選的 k − 1 k-1 k1個器材要大,那麼最後一個器材就選A;否則,就選value第k大的器材。

用python比較容易過,這裡的c的排序和查詢部分我人工優化得不太好,但是思路是這樣,目前用快排(粗糙版)加上簡單查詢可以實現80%Access

python版本100%通過:

N=int(input())
distance = input().split()
exp = input().split()
 
max_to_choose=[]
for i in range(0,N):
    info={'dist':int(distance[i]),'exp':int(exp[i])}
    max_to_choose.append(info)
max_exp=sorted(max_to_choose,key=lambda info:info['exp'],reverse=True) # 按照健身效果排序,由於排序保證是穩定的。所以健身效果相同時,距離大的在後面

max_dist=0
kmax_save=0
kmax_exp=[]
save_index=0
for i in range(0,N):
    if(i>0):
        kmax_save=kmax_save+max_exp[i-1]['exp']
        kmax_exp.append(kmax_save)
        if(max_exp[i-1]['dist']>max_dist):
            max_dist=max_exp[i-1]['dist']
    else:
        kmax_exp.append(0)
    maxval=0
    value=0
    if(save_index<=i):
        for k in range(i,N):
            value=max_exp[k]['exp']+max_exp[k]['dist']*2
            if(value>maxval):
                maxval=value
                save_index=k
    # 從剩下的裡找出2d+V最大的的器材A
    if(max_dist<max_exp[save_index]['dist']):
        kmax_exp[i]=kmax_exp[i]+2*max_exp[save_index]['dist']+max_exp[save_index]['exp']
    else:
        kmax_exp[i]=kmax_exp[i]+2*max_dist+max_exp[i]['exp']
   
for km in kmax_exp:
    print(km)

c程式碼80%通過:

#include <stdio.h>
#include <stdlib.h>
void quick_sort(int s,int k,int a[][2])
{
    if(s<k)
    {
        int i=s,j=k;
        int tmp=a[i][0];
        int tmp2=a[i][1];
        while(i<j)
        {

            while(i<j && a[j][0]<tmp)
            {
                j--;
            }
            if(i<j)
            {
                a[i][0]=a[j][0];
                a[i][1]=a[j][1];
                i++;
            }

            while(i<j && a[i][0]>=tmp)
            {
                i++;
            }
            if(i<j)
            {
                a[j][0]=a[i][0];
                a[j][1]=a[i][1];
                j--;
            }
        }
        a[i][0]=tmp;
        a[i][1]=tmp2;
        quick_sort(s,i-1,a);
        quick_sort(i+1,k,a);
    }
}

void print(int a[][2],int p,int e)
{
    int i=0;
    for(i=p; i<=e; i++)
    {
        printf("exp:%d dist:%d\n",a[i][0],a[i][1]);
    }
    printf("\n");
}

void print_re(int kmax_exp[])
{
    int i=0;
    while(kmax_exp[i])
    {
        printf("%d\n",kmax_exp[i]);
        i++;
    }
}
int info[100000][2]= {0};
int kmax_exp[100000]= {0};
int choosed=0;

int main()
{
    int i=0,n=0;
    scanf("%d",&n);
    for(i=0; i<n; i++)
    {
        scanf("%d",&info[i][1]);
    }
    for(i=0; i<n; i++)
    {
        scanf("%d",&info[i][0]);
    }
    quick_sort(0,n-1,info); //複雜度n2
    //print(info,0,n-1);
    int k=0;
    int max_dist=0;
    int kmax_save=0;

    int save_index=-1;
    for(i=0; i<n; i++)
    {
        //先選k-1個value最大的器材
        if(i>0) //由於前k-1個始終相同,直接儲存結果
        {
            kmax_save=kmax_save+info[i-1][0];
            kmax_exp[i]=kmax_save;
            choosed=i-1; //標記前i-1個為已經選擇
            if(info[i-1][1]>max_dist)
            {
                max_dist=info[i-1][1];//儲存最大距離
            }
        }
        //for(k=0;k<n;k++){
        //    printf("%d ",choosed[k]);
        //}
        //printf("\n");
        //print_re(kmax_exp);
        int exp=info[i][0]; //儲存第k大的經驗值
        int maxval=0;
        int value=0;
        //只有當en+dist*2最大的值被作為前面的
        //選擇了之後才需要重新選擇。從第k個開始找。
        if(save_index<=i)
        {
            for(k=i; k<n; k++)
            {
                //從剩下n-i個裡面的選擇一個en+dist*2最大的
                value=info[k][0]+info[k][1]*2;
                if(value>maxval)
                {
                    maxval=value;
                    save_index=k;//儲存選擇的這個剩下最大的器材的索引
                }
            }
        }
        //printf("maxdist:%d maxval: %d save_index:%d \n",max_dist,maxval,save_index);
        if(max_dist<info[save_index][1])
        {
            kmax_exp[i]=kmax_exp[i]+2*info[save_index][1]+info[save_index][0];
        }
        else
        {
            kmax_exp[i]=kmax_exp[i]+2*max_dist+exp;
        }
    }
    print_re(kmax_exp);
    return 0;
}