题目
一本通题目入口
openjudge题目入口
(注:由于一本通题面描述的可能有些欠缺,所以这里的题面采用openjudge英文翻译后的题面)
题目分析
首先我们来看样例,为什么样例的结果是17呢?首先观察,“5”和“10”较大,作为我们的首选要搞定的目标,那么我们怎样才能将“5”+“10”压小的点呢?我们可以以绝对贪心的角度去想。我若想让“5”+“10”的结果较小,肯定是要让其在一条船上,一起过河,此时我们就只用加“10”的时间了,那么这一下总得让船回来吧,难道要上“5”回来吗?不,肯定不能,所以我们得在河对岸安排一个数较小的人,让他将船再开回来,而送他过去自然又要一个数较小的,而最小的俩是“1”和“2”了,那么谁在对岸谁又送其过去呢?
假设“1”在对岸,则来回花费 m a x ( 1 , 2 ) + 1 + 2 max(1, 2)+1+2 max(1,2)+1+2
假设“2”在对岸,则来回花费 m a x ( 1 , 2 ) + 2 + 1 max(1,2)+2+1 max(1,2)+2+1
这俩结果一样,所以俩方案都行,那么由于搞定的最大的俩,剩下的俩可以一起过去,则这下时间为 m a x ( 1 , 2 ) + ( 1 + 2 ) 或 ( 2 + 1 ) + 10 + 2 = 17 max(1,2)+(1+2)或(2+1)+10+2=17 max(1,2)+(1+2)或(2+1)+10+2=17,刚好17。
经过上述的样例分析,我们得出一个比较省时间的方案(姑且先定为方案1):先让a和b(均为还没过河数中的较大值),一起过河,再通过媒介x(次小值或最小值),让船回来。
可是若次小的数c逼近于我选择的a和b(均为还没过河数中的较大值)时,会出现本来a和b一起乘船不大,但由于加入c这个逼近于a和b,而在算总时间时c要帮助最小值d(媒介x不是c自然是最小值d)过河,此时会算两次c(一次在max时,一次在返回时),在这种情况下总和自然会比其他方案要大的。
那么我若知道此时c会比较大,我肯定选择避开他,可比c还大的不能选,比c小的就一个最小值,故我们只能用最小值d使a和b过河,那么这种方案要最少时间,自然是贪心的让d一个一个的送a和b过河。
所以,为了应对a,b,c逼近m(m>=c 且 a,b>= m)的情况,我们设计如下方案(定为方案2):让最小值d送a和b过河。
最后由于方案1和方案2都是需要题面中n大于等于4的,所以对于n小于4的话可以直接特判断。
还有一个注意,最后未过河的数量可能不是0,所以需要和前面n小于4的情况一样的特判。
正解
此题使用贪心算法。
由于数据非有序,故要先排序,随后从高位进行枚举(未过河的数量小于4时终止),每次都需要比较此时用方案1还是方案2所需的时间小,并存在总时间变量sum里。最后特判n小于4或未过河的数量不是0的情况。
最后的代码:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
inline void write(int X)
{
if(X<0) {X=~(X-1); putchar('-');}
if(X>9) write(X/10);
putchar(X%10+'0');
}
const int N = 1050;
int n;
int a[N];
int main(){
int T = read();
while(T--)
{
n = read();
for (int i = 1; i <= n; ++i) a[i] = read();
int sum = 0;
sort(a + 1, a + n + 1);
for (; n >= 4; n -= 2) //每次送过河两人故每次减2
{
//求方案1和方案2的最小值加入总答案
sum = sum + min(2 * a[1] + a[n] + a[n - 1], a[2] * 2 + a[1] + a[n]);
}
//特判
if (n == 3)
{
//任意俩先过去,这两种小的回来接另一个
//比如说“1”和“3”先去,“1”回去接“2”,这样就是“1”+“2”+“3”
sum = sum + a[1] + a[2] + a[3];
}
else if(n == 2)
{
sum = sum + a[2];
}
else if (n == 1) sum += a[1];
write(sum);
puts("");
}
return 0;
}