其实这个题不算太难,就是好久不刷题了,这个题搞了好长时间==!
题目的主要意思是一群人要过桥,每次至多两个人一起过,过桥需要手电筒,而他们只有一个手电筒,这意味着每次都要有一个人把手电筒送回来。每个人的速度不同,过桥用的时间也不一样,求最短的时间。
主要先理解算法思路:先分析四个人过河的情况,然后再推广到 n 个人。
1. 先讨论四个人的情况,一共是有两种方案的:
假设四个步速为a < b < c < d,
方案一:AB过A回 CD过B回 AB过,时间为 b + a + d + b + b;
方案二:AC过A回 AD过A回 AB过 ,时间为 c + a + d + a + b;
比较两者时间,关键在 2*b 与 a+c 的大小 。
2. 当人数大于四时,四步一组,每次优先将最慢 的两个送到对岸;当人数小于四时,单独计算。
/**********************************************
** 过桥问题 **
** 先讨论四个人的情况,一共是有两种方案的, **
** 假设四个步速为a < b < c < d, **
** 方案一:AB过A回 CD过B回 AB过 **
** 方案二:AC过A回 AD过A回 AB过 **
** 比较两者时间,关键在 2*b 与 a+c 的大小 **
** 当人数大于四时,四步一组,每次优先将最慢 **
** 的两个送到对岸;人数小于四时,单独计算 **
**********************************************/
#include<stdio.h>
#include<algorithm>
using namespace std;
#define MAXPEOPLE 1000
int s[MAXPEOPLE];
int main()
{
int n, i, j, count, time;
while(scanf("%d", &n) != EOF)
{
for(i = 0; i < n; i++)
scanf("%d", &s[i]);
/* 读入数据,并按速度由小到大进行排序 */
sort(s, s+n);
/* 记录已经过河的人数,过河时间; **
** j 用来标记未过河中最慢的人 , **/
count = 0;
time = 0;
j = n-1;
/* 如果人数大于等于4进入循环 */
while(count <= n-4)
{
if(2*s[1] < s[0] + s[j-1])
/* 选择方案一过河 */
time += s[1] + s[0] + s[j] + s[1];
else
/* 选择方案二过河 */
time += s[j-1] + s[0] + s[j] + s[0];
count += 2;
j -= 2;
}/* 只要进入循环体,出循环后必然是还有三个人或两个人未过河 */
switch(n-count)
{
case 1 : {time += s[0]; break;}
case 2 : {time += s[1]; break;}
case 3 : {time += s[0] + s[1] + s[2]; break;}
}
/* 处理输入输出 */
printf("%d\n", time);
count = 0;
j = n-1;
/* 如果人数大于等于4进入循环 */
while(count <= n-4)
{
if(2*s[1] < s[0] + s[j-1])
{
/* 选择方案一过河 */
/* AB过A回 */
printf("%d %d\n%d\n", s[0], s[1], s[0]);
i += 3;
/* CD过B回 */
printf("%d %d\n%d\n",s[j-1], s[j], s[1]);
}
else
{
/* 选择方案二过河 */
/* AC过A回 */
printf("%d %d\n%d\n", s[0], s[j-1], s[0]);
/* AD过A回 */
printf("%d %d\n%d\n", s[0], s[j], s[0]);
}
count += 2;
j -= 2;
}/* 进入循环体的情况,出循环后必然是还有三个人或两个人未过河 */
switch(n-count)
{
case 0 : {printf("0 0\n"); break;}
case 1 : {printf("%d\n", s[0]); break;}
case 2 : {printf("%d %d\n", s[0], s[1]); break;}
case 3 : {printf("%d %d\n%d\n%d %d\n", s[0], s[1], s[0], s[0], s[2]); break;}
}
}
return 0;
}
/* AC不了,一直WA,不知道哪儿错了 */
/**********************************************
** 首先是,写代码过程中犯很多小毛病,在循环体内 **
** 写的代码一定注意写成随循环变量变化的,我在while中的 **
** if 分支判断条件,最开始居然写成死的了,s[2]都写上去了 **
**********************************************/
/************************************************
** 第二点是,这道题题目上没说是多个测试用例,但 ZOJ 中 **
** 估计是默认都是多个输入用例,开头必须加上while(!=EOF) **
************************************************/
/***********************************************
** 第三,写代码过程中发现 VS 编译器中,如果 printf 语句 **
** 中使用 a[i++] 类似的语句,i 的值的计算词序是无法得知 **
** 的,输出结果并非自己想象的那样,故以后杜绝此类写法。 **
***********************************************/