【快手筆試題】程式設計題-健身
技術標籤:演算法
[程式設計題]健身
因為公司有免費健身福利,快手程式設計師老鐵們都很愛健身,而且他們健身時像工作一樣充滿效率。
他們把健身過程神奇的簡化了出來:健身有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)
而
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+en−1)+max(en)+max(dist∗2)
此時可看出,前n-1個一定是val的最大值,而
m
a
x
(
e
n
)
+
m
a
x
(
d
i
s
t
∗
2
)
max(en)+max(dist*2)
1.
e
n
+
d
i
s
t
∗
2
en+dist*2
en+dist∗2的和的值最大,否則
2.
v
a
l
val
val最大,
d
i
s
t
dist
dist是前面的某個n的值。
所以應該找出前
k
−
1
個
k-1個
k−1個最大的E,剩下的如果器材A的
d
d
d比前面選的
k
−
1
k-1
k−1個器材要大,那麼最後一個器材就選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;
}