zoukankan      html  css  js  c++  java
  • 【题解】p1809 过河问题

    原题传送门

    题目分析

    • 现有n个人在东岸,要过河去西岸。开始东岸有一艘船,船最多可承载2人,过河时间以耗时最长的人所需时间为准。

      给定n个人的过河时间a,求所有人从东岸到西岸所需的最短时间。

    • (n=2)时,易得答案为(a[2])。但问题在于当(n>2)如何解决。

    贪心分析

    • 对所有数据从小到大排序。

    • 从小规模数据出发,当(n=3)时,不难想到可以先用(a[1])(a[3])送过去,再让(a[1])回来,这样就回归了(n=2)的情况。

    • (n>3)时情况略为复杂,我们考虑推导问题的几个简单性质。

      1. 对于每次船在西岸时,如果需要某个人将船送回来,则优先让西岸a最小的(dalao)回来。

        证明:假设西岸有过河时间(a[1],a[2],a[3])的三个人,则让(a[1])回来,必然导致东岸后续的子问题最优。

        如此便得到一个简单的贪心,我们便无需考虑回来的情况,只需要思考如何将人送过去。

        重要推论:在问题结束前,不甘寂寞的(dalao) (a[1])不可能被留在西岸。也就是说,(a[1])只要过去,就必然要将船送回来。

      2. 对于(4<=i<=n)的所有(a[i-1]),它到西岸只有两种可能方式:自己和(a[1])过去,或者自己和(a[i])过去。

        对于第一种方式:就相当于(a[i-1])自己过去,(a[1])负责送船回来,代价(a[i-1]+a[1])

        对于第二种方式:如果不希望(a[i-1])被贡献到答案中,则只能选择一个(j>i-1)的小蒟蒻(a[j])来当(a[i-1])的拖油瓶。

        但问题在于,过弱的蒟蒻(a[j])不能和(dalao) (a[i-1])玩,或者说(dalao) (a[i-1])不能选择太弱的(a[j])来当拖油瓶,否则代价会过大。因此(a[i-1])只能选择(a[i])来当它的拖油瓶。

        那么两人过去以后,谁给他们送船回来呢?由于(a[1])不可能在西岸等着他们,因此需要提前让(a[1])(a[2])过去,留(a[2])为他们送船。代价(a[2]+a[1]+a[i]+a[2])

      3. 由此,我们可以得到状态转移方程:$$f[i]=min(f[i-1]+a[i]+a[1],f[i-2]+a[2]+a[1]+a[i]+a[2])$$

      4. 几乎每一篇题解都提到了这个方程,那么问题来了,为什么(f[i])(f[i-1]和f[i-2])中取一转移即可,而不能继续考虑到(f[i-3])

        我们考虑已知(f[i-3]),然后新来了三个蒟蒻,对于(a[i-2]),他不可能会带(a[i])过河,也就是要么自己走,要么带(a[i-1])走。也就是说(a[i-2])的决策与(a[i])无关。

        因此求(f[i])时,只要考虑(a[i-1])的决策即可,也就是从(f[i-1])(f[i-2])两个状态中取一转移即可。

    code:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAXN=100010;
    int n,a[MAXN],f[MAXN];
    
    int main()
    {
    //	freopen("in.txt","r",stdin);
    	
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)scanf("%d",a+i);
    	
    	f[1]=a[1];
    	f[2]=a[2];
    	f[3]=a[3]+a[1]+a[2];
    	
    	for(int i=4;i<=n;++i)f[i]=min(f[i-1]+a[i]+a[1],f[i-2]+a[2]+a[1]+a[i]+a[2]);
    	
    	printf("%d
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    js 删除字符串中所有空格
    jquery easyui datagrid 设置设置在选中的所有行中只选择第一行
    编译Linux内核时出现错误gcc: error: elf_i386: No such file or directory
    AD9打印丝印层
    s3c2410 board.c分析
    2010.03 u-boot--Makefile完全分析
    mini6410移植--uboot移植(2)
    mini6410移植--uboot移植(1)
    uboot之uboot.lds文件分析
    Linux启动过程
  • 原文地址:https://www.cnblogs.com/-SingerCoder/p/12872232.html
Copyright © 2011-2022 走看看