G - Crossing River(贪心)

G - Crossing River(贪心)

题意:每次两个人坐船过河,每次过河的时间取速度较慢的那个人,问所有人过河所需最短时间。

思路:经典贪心题目,我们将时间进行从小到大排序,根据贪心思想,我们肯定需要人过了河带船回来,显然肯定要速度快的带船回来所用时间更少,所以每次我们需要运速度较慢的人过去然后他们就不用管了。接下来对特殊情况进行讨论。

n = 1 n=1 时显然 a n s = a [ 1 ] ans=a[1]

n = 2 a n s = a [ 2 ] n=2\rightarrow ans=a[2]

n = 3 n=3 时,显然船要回一次,所以肯定是速度最快的人回,

a n s = a [ 1 ] + a [ 2 ] + a [ 3 ] ans=a[1]+a[2]+a[3]

n 4 n\geq4 时,我们可以通过每次运两个(最慢和次慢)将情况变为前面三种情况,此时要分两种情况

m e t h o d 1 : method1: 类比 n = 3 n=3 的方法, a n s = a [ 1 ] × 2 + a [ s l o w e s t ] + a [ s l o w e s t 1 ] ans=a[1]\times2+a[slowest]+a[slowest-1]

m e t h o d 2 method2 :通过让最慢和次慢的一起过河,从而减少一次次慢的时间,但要增加一倍次快的时间,方法是先让最快和次快过河,最快回来,最慢和次慢过河,次快再回来。即 a n s = a [ 1 ] + a [ 2 ] × 2 + a [ s l o w e s t ] ans=a[1]+a[2]\times2+a[slowest]

综上问题得到解决。

时间复杂度: O ( n l o g n + n 2 ) O(nlogn+\dfrac{n}{2})

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm> 
#include<map>
using namespace std;
typedef long long ll;
const int N=1e3+10;
#define mst(a) memset(a,0,sizeof a)
int a[N];
using namespace std;
int main()
{
	int t,n;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		int ans=0,i;
		for(i=1;i<=n;i++) scanf("%d",&a[i]);
		sort(a+1,a+n+1);
		for(i=n;i>3;i-=2)//n>=4情况 
			if(a[1]*2+a[i-1]+a[i]<a[1]+a[2]*2+a[i])//两种method 
				ans+=a[1]*2+a[i-1]+a[i];
			else ans+=a[1]+a[2]*2+a[i];
		if(i==3) ans+=a[1]+a[2]+a[3];//n<=3的情况. 
		else if(i==2) ans+=a[2];
		else ans+=a[1];
		printf("%d\n",ans);
	}
	return 0;
}
原创文章 201 获赞 165 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/106107786