第四章上机实践

 
一、题目:最优合并问题 
二、题目描述:

题目来源:王晓东《算法设计与分析》

给定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;

四、算法空间和时间复杂度分析

扫描二维码关注公众号,回复: 4276433 查看本文章

创建了两个数组,所以在此空间复杂度为O(k2),输入数组的时候的时间复杂度为O(k),第一次直接排序的时候时间复杂度为O(k *log k),第二次在进行求最好的情况的比较次数的时候的空间复杂度为O(k*k*log k),最后进行最坏情况的比较次数的计算的时候时间复杂度为O(k),其他的计算时间复杂度为常数O(1);故总的时间复杂度为O(k*k*log k);

五、心得体会

在解决问题的时候最重要的是完全读懂问题再进行解题,把思路整理清晰后再打代码尝试一下,不要随意扫过题目或者不清楚题目的真正要求的东西就叫你行求解,那将会浪费很多时间,还有就是最好有个人一起打代码,一起探讨,那样子在解决问题的时候会走少点的弯路。在贪心算法这方面,你首先是得抓住问题的关键点在哪里,找出贪心性质,才能一步一步的将子问题求解出来。

猜你喜欢

转载自www.cnblogs.com/chenhanwu/p/10033463.html