[关闭]
@geek-sjl 2018-10-08T05:14:20.000000Z 字数 1459 阅读 378

18图灵班作业4-编程

有两个向量 v1=(x1, x2, ..., xn)和 v2=(y1, y2, ..., yn),允许任意交换 v1 和 v2 各自的分量的顺序。请计算 v1 和 v2 的内积 x1y1+...+xnyn 的最小值。

直觉判断这个可以用贪心解法,毕竟暴力枚举是不可能的,下面证明以下贪心策略(可能)正确:
将v1按从小到大排序,v2按从大到小排序,则有最终结果为

首先,我们可以把其中一个向量看成是不变的,例如v1是按从小到大排序的,改变v2的排列顺序,求两个向量内积的最小值。
由上面的证明知道,当以v2按从大到小排序为初态时,再调换v2中某两个元素的位置,内积会增大。
又因为可以通过继续两两调换v2中其他的任意两个元素从而产生v2的全排列,而根据上一行的结论,内积会变的更大,因此v2按从大到小排序,v1按从小到大排序时内积最小。

还有一点,进行第二次调换的时候v2不是已经不是标准序了吗?“再调换v2中某两个元素的位置,内积会增大”这个结论仍然成立的理由是:我们把v1、V2中未相乘的元素按原先顺序排列组成一个新的序列,则该序列仍然满足一开始的前提————“v1从小到大,v2从大到小”。

综上,v1从小到大,v2从大到小排序后的点积最小。当v2中任意两个元素调换顺序(逆序对?)的时候,点积会增大。

由此可知,调换任意两个元素的顺序都会使结果变大
我们可以接着把未被调换的元素看成新的数列,它们仍然是标准序,那么接着调换它们中的任意两个,结果又会接着变大,因此,以上结论成立

最后是代码

  1. #include <algorithm>
  2. #include <cstdio>
  3. using namespace std;
  4. bool LessComparer(int t1,int t2){
  5. return t1<t2;
  6. }
  7. bool GreatComparer(int t1,int t2){
  8. return t1>t2;
  9. }
  10. int main(){
  11. int n;
  12. scanf("%d",&n);
  13. int* vector1;
  14. int* vector2;
  15. vector1=(int*)malloc(sizeof(int)*n);
  16. vector2=(int*)malloc(sizeof(int)*n);
  17. sort(vector1,vector1+n,LessComparer);
  18. sort(vector2,vector2+n,GreatComparer);
  19. int ans=0;
  20. for(int i=0;i<n;i++){
  21. ans+=vector1[i]*vector2[i];
  22. }
  23. printf("%d\n",ans);
  24. return 0;
  25. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注