poj--1700

Crossing River
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 12274 Accepted: 4647

Description

A group of N people wishes to go across a river with only one boat, which can at most carry two persons. Therefore some sort of shuttle arrangement must be arranged in order to row the boat back and forth so that all people may cross. Each person has a different rowing speed; the speed of a couple is determined by the speed of the slower one. Your job is to determine a strategy that minimizes the time for these people to get across.

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. The first line of each case contains N, and the second line contains N integers giving the time for each people to cross the river. Each case is preceded by a blank line. There won't be more than 1000 people and nobody takes more than 100 seconds to cross.

Output

For each test case, print a line containing the total number of seconds required for all the N people to cross the river.

Sample Input

1
4
1 2 5 10

Sample Output

17
 
题目来源:http://poj.org/problem?id=1700
 
考查知识点:贪心算法
 
解体思路:这算是一道经典的贪心题目,但我做这道题时,完全没思路,贪心的题要求有很好的思维能力大哭。现在先解释一下为什么样例的结果会是17,而不是19。首先1,2过河,1回来,time=3;再5,10,过河,2回来,time=15;最后1,2过河,time=17。由此可见得,在过河时,可以先把速度最慢的人送过去,但在送过去时有两种方法。一种是反复利用最快的人,一种是在河对岸留一个第二快的人,与第一块的人相互配合。
最佳方案构造法:以下是构造N个人(N≥1)过桥最佳方案的方法:  
> 1) 如果N=1、2,所有人直接过桥。  
> 2) 如果N=3,由最快的人往返一次把其他两人送过河。  
> 3) 如果N≥4,设A、B为走得最快和次快的旅行者,过桥所需时间分别为a、b;而Z、Y为走得最慢和次慢的旅行者,过桥所需时间分别为z、y。那么    当2b>a+y时,使用模式一将Z和Y移动过桥;    当2b<a+y时,使用模式二将Z和Y移动过桥;当2b=a+y时,使用模式一将Z和Y移动过桥。这样就使问题转变为N-2个旅行者的情形,从而递归解决之。
 
代码如下:
#include<stdio.h>
#include<algorithm>
using namespace std;
long long v[1010];
int cmp(int a,int b)
{
	return a<b;
}
int main()
{
	int t,n,i;
	long long sum;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(i=0;i<n;i++)
		scanf("%lld",&v[i]);
		sort(v,v+n,cmp);
		sum=0;
//		if(n<=2)
//		printf("%lld\n",v[n-1]);
//		else if(n==3)
//		printf("%lld\n",v[0]+v[1]+v[2]);
	
			while(n>=4)
			{
				if(2*v[1]>=v[0]+v[n-2])
				sum+=2*v[0]+v[n-2]+v[n-1];
			    else
			    sum+=v[1]+v[0]+v[n-1]+v[1];
			    n-=2;
			}
	        if(n==3)
	        {
	        	sum+=v[0]+v[1]+v[2];
	        }
	        else if(n==2)
            {
            	sum+=v[1];
            }
            else if(n==1)
            sum+=v[0];
		 printf("%lld\n",sum);    
		}
	return 0;
}

再贴一个别人写的dp,太牛了
代码如下:
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int data[10050],dp[10050];
int One(int i)
{
return  data[i]+data[0];
}//利用跑得最快的人 
int Two(int i)
{
return data[i+1]+data[0]+2*data[1];
}//最快于第二快配合 
int main()
{
	int T,n,i,j,ans,tmp;
	cin>>T;
	while(T--){
		scanf("%d",&n);
		for(i=0;i<n;i++) scanf("%d",&data[i]);
		sort(data,data+n);
		dp[0]=data[0],dp[1]=data[1],dp[2]=data[0]+data[1]+data[2];
		for(i=3;i<n;i++)
			dp[i]=min(dp[i-1]+One(i),dp[i-2]+Two(i-1));
		printf("%d\n",dp[n-1]);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值