ZOJ 1877 Bridge

      其实这个题不算太难,就是好久不刷题了,这个题搞了好长时间==!


       题目的主要意思是一群人要过桥,每次至多两个人一起过,过桥需要手电筒,而他们只有一个手电筒,这意味着每次都要有一个人把手电筒送回来。每个人的速度不同,过桥用的时间也不一样,求最短的时间。


     主要先理解算法思路:先分析四个人过河的情况,然后再推广到 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 的值的计算词序是无法得知  **
** 的,输出结果并非自己想象的那样,故以后杜绝此类写法。  **
***********************************************/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值