一、题目:最优合并问题
二、题目描述:
题目来源:王晓东《算法设计与分析》
给定k 个排好序的序列, 用 2 路合并算法将这k 个序列合并成一个序列。 假设所采用的 2 路合并算法合并 2 个长度分别为m和n的序列需要m+n-1 次比较。试设 计一个算法确定合并这个序列的最优合并顺序,使所需的总比较次数最少。 为了进行比较,还需要确定合并这个序列的最差合并顺序,使所需的总比较次数最多。
三、算法描述:
1、代码:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 int main() 5 { 6 int k; 7 cin>>k; 8 int a[k],b[k]; 9 for(int i=0;i<k;i++) 10 { 11 cin>>a[i]; 12 } 13 sort(a,a+k); 14 for(int i=k-1,j=0;i>=0;i--,j++) 15 { 16 b[j]=a[i]; 17 } 18 int sum1=0,sum2=0; 19 for(int i=0;i<k-1;i++) 20 { 21 a[i+1]=a[i]+a[i+1]; 22 sum1+=a[i+1]; 23 sort(a+i,a+k); 24 } 25 for(int j=0;j<k-1;j++) 26 { 27 b[j+1]=b[j]+b[j+1]; 28 sum2+=b[j+1]; 29 } 30 cout<<sum2-k+1<<" "; 31 cout<<sum1-k+1<<endl; 32 return 0; 33 }
2、算法解析:
有k个数组待归并,本算法在解决问题的时候的关键点将排好序后(以k个数组的长度进行的排序,升序一种,升序求最好的情况,降序一种,降序求最坏的情况)的序列进行,组个迭代,将后一位的加上当前的数然后覆盖掉后一位的值,进而将值赋给sum1进行累加,在求升序的(即求最好的情况的时候)时候,由于每一次覆盖后一位之后,序列中就不一定还是升序的了,所以应当进行重新排序,之后再反复的进行迭代和累加(如,3,5,6,9这个序列将5用哪5+3=8覆盖之后,序列变成3,8,6,9就不再是一个升序了,所以在此用algorithm头文件里的sort快排进行排序)。而每两个数组归并比较的次数是m+n-1,所以,在此我们在过程中将sum累加了起来,并没有进行-1,由于进行了k-1次的不同数组的归并,所以在此k个数组的归并的最少的次数为sum1-k+1;
对于降序的序列进行最坏的次数的运算,由于,最大的两个加起来还是最大的,所以在此我们不需要在进行排序了,只需要跟升序累加一样子进行迭代和sum2的累加就行了,也是通过k-1次的不同数组的,所以最好的情况的比较次数为sum2-k+1;
四、算法空间和时间复杂度分析
创建了两个数组,所以在此空间复杂度为O(k2),输入数组的时候的时间复杂度为O(k),第一次直接排序的时候时间复杂度为O(k *log k),第二次在进行求最好的情况的比较次数的时候的空间复杂度为O(k*k*log k),最后进行最坏情况的比较次数的计算的时候时间复杂度为O(k),其他的计算时间复杂度为常数O(1);故总的时间复杂度为O(k*k*log k);
五、心得体会
在解决问题的时候最重要的是完全读懂问题再进行解题,把思路整理清晰后再打代码尝试一下,不要随意扫过题目或者不清楚题目的真正要求的东西就叫你行求解,那将会浪费很多时间,还有就是最好有个人一起打代码,一起探讨,那样子在解决问题的时候会走少点的弯路。在贪心算法这方面,你首先是得抓住问题的关键点在哪里,找出贪心性质,才能一步一步的将子问题求解出来。