贪心算法-数列极差问题
【题目描述】
在黑板上写了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即可得解。