- 描述
-
在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。
-
输入
- 第一行是一个整数T(1<=T<=20)表示测试数据的组数
每组测试数据的第一行是一个整数N(1<=N<=1000)表示共有N个人要过河
每组测试数据的第二行是N个整数Si,表示此人过河所需要花时间。(0<Si<=100) 输出 - 输出所有人都过河需要用的最少时间 样例输入
-
1 4 1 2 5 10
样例输出 -
17
- 第一行是一个整数T(1<=T<=20)表示测试数据的组数
分析:
现在假设n个人的过河时间已经从小到大排好序用数列 a1 ,a2 ,a3 ,a4 ,... , an ;
当(n <= 2) ans = a[n] ;
当(n > 2) 时:
(1) n 是偶数
a3 ,a4 怎么过
肯定是a1 , a2 先过去再a1回来。
(a)a1和a3 一起过,再a1回来和a4一起过 。
总时间 time1 = a1 + a3 + a1 + a4 ;
(b)a3和a4一起过再a2回来和a1一起过。
总时间 time2 =a1 + a4 + a2 + a2 ;
time = min(time1 , time2) ;
(2) n 是奇数两两一起过会有一个人打单。
现在的问题是a3打单还是an。
现在假设 n = 5 .
a5打单 time1 = min((a1 + a4 + a2 + a2 ) ,(a1 + a3 + a1 + a4) ) + a1 + a5
a3打单 time2 = min((a1 + a5 + a2 + a2 ) , (a1 + a4 + a1 + a5)) + a1 + a3 ;
比较time1 和 time2
当 time1 = a1 + a1 + a2 + a2 + a4 + a5 ;
time2 = a1 + a1 + a2 + a2 + a3 + a5 ;
所以a3打单好。
得出要从后面开始 。
代码如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std ;
#define M 1000 + 10
int a[M] ;
int n ;
int solve()
{
int b,c,ret,num,x,y;
ret = 0 ;
sort(a + 1 , a + n +1) ;
if(n <= 2)
return a[n] ;
b = a[1] ;
c = a[2] ;
ret += a[2] ;
num = n - 2 ;
for(int i = n ;i >= 3 ; --i)
{
if(num >= 2)
{
x = b + a[i] + c + c ;
y = b + b + a[i] + a[i - 1] ;
if(x > y)
ret += y ;
else ret += x ;
num -= 2 ;
--i ;
}
else
{
ret += b + a[i] ;
}
}
return ret ;
}
int main()
{
int cas ;
int ans ;
scanf("%d",&cas) ;
while(cas--)
{
scanf("%d",&n) ;
for(int i = 1 ;i <= n ; ++i)
{
scanf("%d",&a[i]) ;
}
ans = solve() ;
printf("%d\n",ans) ;
}
return 0 ;
}