贪心算法-数列极差问题
【题目描述】
在黑板上写了N个正整数做成的一个数列,进行如下操作:每一次擦去其中的两个数a和b,然后在数列中加入一个数a×b+1,如此下去直至黑板上剩下一个数,在所有按这种操作方式最后得到的数中,最大的max,最小的为min,则该数列的极差定义为M=max-min。
编程任务:对于给定的数列,编程计算出极差M。
输入输出样例:
输入:
4
2 1 4 3
输出:
13
【算法分析】
当看到此题时,我们会发现求max与求min是两个相似的过程。若我们把求解max与min的过程分开,着重探讨求max的问题。
下面我们以求max为例来讨论此题用贪心策略求解的合理性。
讨论:假设经(N-3)次变换后得到3个数:a ,b , max'(max'≥a≥b),其中max'是(N-2)个数经(N-3)次f变换后所得的最大值,此时有两种求值方式,设其所求值分别为 z1,z2,则有:z1=(a×b+1)×max'+1,z2=(a×max'+1)×b+1所以z1-z2=max'-b≥0若经(N-2)次变换后所得的3个数为:m,a,b(m≥a≥b)且m不为(N-2)次变换后的最大值,即m<max'则此时所求得的最大值为:
z3=(a×b+1)×m+1此时z1-z3=(1+ab)(max'-m)>0 所以此时不为最优解。
所以若使第k(1≤k≤N-1)次变换后所得值最大,必使(k-1)次变换后所得值最大(符合贪心策略的特点2),在进行第k次变换时,只需取在进行(k-1)次变换后所得数列中的两最小数p,q施加f操作:p←p×q+1,q←∞即可(符合贪心策略特点1),因此此题可用贪心策略求解。在求min时,我们只需在每次变换的数列中找到两个最大数p,q施加作用 f:p←p×q+1,q←-∞即可.原理同上。
这是一道两次运用贪心策略解决的一道问题,它要求选手有较高的数学推理能力。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int [] n = new int[N];
int max,min;
for (int i = 0; i < N; i++) {
n[i] = sc.nextInt();
}
int[] nclone = n.clone();//拷贝一次数组,因为有两次操作,分别求max和min。
//求出MAX:
int m = 0;
while(m != N-1){
for (int i = m; i < m+2; i++) {//循环为m到m+2,因为每次只要求出两个最小的值。
for (int j = i+1; j < n.length; j++) {
if(n[j]<n[i]){
int temp = n[j];
n[j] = n[i];
n[i] = temp;
}
}
if(i==m+1){
n[i] = n[i-1]*n[i]+1;
}
}
m++;
}
max = n[N-1];
//求出MIN:
m = 0;//重新初始化m。
while(m != N-1){
for (int i = m; i < m+2; i++) {
for (int j = i+1; j < nclone.length; j++) {
if(nclone[j]>nclone[i]){//事实上只是将小于号改为大于号即可。
int temp = nclone[j];
nclone[j] = nclone[i];
nclone[i] = temp;
}
}
if(i==m+1){
nclone[i] = nclone[i-1]*nclone[i]+1;
}
}
m++;
}
min = nclone[N-1];
//MAX - MIN :
System.out.println(max - min);
}
}
编程的思路:
每次排序仅排除最小(或最大)的两个数,然后将二者运算的结果放在第二个数的位置,然后从第二个数的位置开始往后排序,重复上述过程。最后得到数组最末尾的那个数就是运算的MAX(或MIN)的结果。MAX-MIN即可得解。