问题描述
解题思路
(按照课本上尝试写证明,欢迎指正)
采用接水时间最短者先接水的贪心选择策略,从而使得n个人的平均等待时间最小。算法复杂度为O(nlogn)。
(1)贪心选择性质
设每个人已经依其接水时间从小到大排序,即(T1<T2<…<Tn),假设排队接水问题的最优解为按照顺序T2,T1,T3,T4,…,Tn的顺序接水,n个人的平均等待时间为:
如果按照接水时间最短者先接水的贪心选择策略,n个人的平均等待时间为:
由于T1<T2,所以所给出的贪心解不必最优解差,因此贪心选择性质成立。
(2)最优子结构性质
设T1,T2,T3,…,Tn的顺序接水是排队接水问题的满足贪心选择性质的最优解,则当第一个人接过水后,假设T2,T3,T4,…,Tn的顺序接水不是相应排队接水子问题的最优解,而是存在一个子问题最优解,使得其剩余n-1人在子问题中的等待总时间为min,即min< T2*(n-2)+⋯+T(n-1)*1,则总问题n个人的等待总时间为:min+T1*(n-1)< T1*(n-1)+T2*(n-2)+⋯+T(n-1)*1,与假设矛盾。故排队接水问题具有最优子结构性质。
代码实现
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int N=1005;
int T[N];
int n;
int partition(int a[],int p,int r){
int i=p,j=r+1;
int x=a[p];
while(true){
while(a[++i]<x&&i<r) ;
while(a[--j]>x);
if(i>=j) break;
//Swap(a[i],a[j]);
int t=a[i];
a[i]=a[j];
a[j]=t;
}
a[p]=a[j];
a[j]=x;
return j;
}
void QuickSort(int a[],int p,int r){
if(p<r){
int q = partition(a,p,r);
QuickSort(a,p,q-1); //左排
QuickSort(a,q+1,r); //右排
}
}
int main(){
cin>>n; //输入人数
for(int i=1;i<=n;i++) scanf("%d",&T[i]); //输入接水时间
QuickSort(T,1,n);//从小到大快排
long long int sum=0;
for(int i=1;i<=n-1;i++) sum+=T[n-i]*i;
double res=(double)sum/(double)n;
printf("%.1lf",res);
return 0;
}