交换两个向量之间的值,使两个向量的max_elements之和最小

时间:2016-09-23 12:14:31

标签: c++ algorithm

这是来自Codechef的问题,但请耐心等待。 https://www.codechef.com/ZCOPRAC/problems/ZCO16001

比赛是为了准备在印度举行的区域计算奥林匹克运动会,所以它不是一场竞争性的比赛,我可以从中获得这样的比赛。只需要一些帮助就可以看出我的代码有什么问题,因为我有一种感觉,我忽略了一些大而愚蠢的东西。 :P

所以基本上这个问题总结为这个。

  

让我们说有两个向量或数组。你需要交换   它们之间的元素使得它们的最大元素之和   是最低的。但是,您最多可以交换K次。然后输出   这笔钱的价值。

我的方法很简单。取Vector1(V1)中的最大数字,并将其与V2中的最低值交换。添加每个的最高值。这样做,但这次交换V2中的最高数字与V1中的最低数字。添加每个的最高值。更好的交换将是具有最低总和的那个并且从那里继续K次。

例如:

V1 = 5 6 7 9

V2 = 9 10 5 4

在这种情况下,如果K = 1 我首先用V2的4交换V1的9。这给出了:

V1 = 5 6 7 4

V2 = 9 10 5 9

最高数字的总和为17,与之前的19相比。我可以做的第二次交换是来自V2的10和来自V1的5:

V1 = 10 6 7 4

V2 = 9 5 5 9

这将sum总和为19,所以第一次交换更好,输出应为17。

这是我的解决方案:

#include <iostream>
#include <vector>
#include <algorithm>
#define print(vec) for (int i  = 0; i < vec.size(); i++) { cout << vec[i] << " "; } cout << endl;
using namespace std;

vector <long long int> s1, s2;

inline long long int calc(vector <long long int> v1, vector<long long int> v2) {
    return *max_element(v1.begin(), v1.end()) + *max_element(v2.begin(), v2.end());
}
int main(){


    long long int n, k;
    cin >> n >> k;
    long long int x;
    for (unsigned int i = 0; i < n; i++) {
        cin >> x;
        s1.push_back(x);
    }
    for (unsigned int i = 0; i < n; i++) {
        cin >> x;
        s2.push_back(x);
    }
    while (k--) {

        vector <long long int> b1(s1);
        vector <long long int> b2(s2);
        long long int skewb = calc(b1,b2);

        vector <long long int> v1(s1);
        vector <long long int> v2(s2);

        auto mn1 = minmax_element(v1.begin(), v1.end());
        auto mn2 = minmax_element(v2.begin(), v2.end());

        iter_swap(mn1.second, mn2.first);

        b1 = vector <long long int> (v1);
        b2 = vector <long long int> (v2);
        skewb = calc(v1,v2);

        v1 = vector <long long int> (s1);
        v2 = vector <long long int> (s2);
        mn1 = minmax_element(v1.begin(), v1.end());
        mn2 = minmax_element(v2.begin(), v2.end());

        iter_swap(mn2.second, mn1.first);
        if (calc(v1,v2) <= skewb) {
            b1 = vector <long long int> (v1);
            b2 = vector <long long int> (v2);
        }

        if (b1 == s1 && b2 == s2) cout << "LOL" << endl;
        s1 = vector <long long int> (b1);
        s2 = vector <long long int> (b2);
    }



    cout << calc(s1, s2) << endl;
}

请注意,所有交换,即K.所以,即使当前的安排是最好的,它仍然会交换一些值。当前的安排是最好的,我早先打破了。这样做的原因是因为除了TWO之外我正在测试所有测试用例!猜猜什么更令人讨厌,一个来自每个任务! :( 所以我意识到必须完成所有K开关。然而即使现在我得到2个错误的测试用例,肯定有一些我忽略的东西。

知道它是什么吗? 链接到解决方案:https://www.codechef.com/viewsolution/11574501

顺便说一句,任务1的K = 1。

3 个答案:

答案 0 :(得分:1)

您的代码的问题是您在交换之间更改数组,因此可以在数组之间来回交换一个项目。我的意思是在第一次交换时你将元素 x 从array1放到array2中,在下一次交换中你可能会再次交换它。

此外,您还进行了大量的矢量复制,这会导致代码效率低下。即使您的代码逻辑正确,您的代码也不会超过时间限制,因为您的方法是O(n 2 )。

首先请注意,最佳答案是当一个数组中的所有元素都大于另一个数组中的所有元素时。

  • 对两个数组进行排序
  • for x 从0到 k
    • 假设第一个数组的 x 最小元素与 x 第二个数组的最大元素交换。
    • result = min(result,max(result,max(first array)+ max(second array))
    • 假设将 x 第一个数组的最大元素与 x 第二个数组的最小元素交换。
    • result = min(result,max(result,max(first array)+ max(second array))
  • 结果将保留最终答案

由于两个数组都已排序,因此您可以在假设交换后通过一次比较找到数组的最大元素。

V1 = 5 6 7 9 -> 5 6 7 9
V2 = 9 10 5 4 -> 4 5 9 10

x = 0   no swaps: result = V1[size-1] + V2[size-1]
x = 1 
        result = max(V1[size-1], V2[size-1]) + max(V1[0], V2[size-2])
        result = max(V1[size-2], V2[0]) + max(V1[size-1],V2[size-1])
x = 2 
        result = max(V1[size-1], V2[size-1]) + max(V1[1], V2[size-3])
        result = max(V1[size-3], V2[1]) + max(V1[size-1],V2[size-1])
...

这是公认的实施方式:

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
using namespace std;


int main()
{
    int n,k;
    cin>>n>>k;

    vector<int> v[2];
    for ( int i=0;i < 2;++i ){
        for ( int j=0;j<n;++j ){
            int temp; cin>> temp;
            v[i].push_back(temp);
        }
    }

    sort(v[0].begin(),v[0].end());
    sort(v[1].begin(),v[1].end());

    int result = v[0].back() + v[1].back();

    for ( int i=1; i<=k; ++i ){
        int t = max(v[0][n-1],v[1][n-1]) + max(v[0][i-1],v[1][n-1-i]);
        result = min(result,t);
        t = max(v[0][n-1-i],v[1][i-1]) + max(v[0][n-1],v[1][n-1]);
        result = min(result,t);
    }

    cout << result << endl;
}

答案 1 :(得分:-1)

如果我理解正确,你想要最小化两个最大元素的总和,每个数组一个。你只能进行K交换。

假设数组已排序(这不会改变算法)。 选择k元素依次较小的数组。让我们调用这个数组S和另一个数组B. 在每次交换中,从数组S中获取最大元素,并与数组B中的最小元素交换。 如果在某个时间,阵列S中的所有元素都小于B停止。

说明:我们知道两个数组中的最大元素都在解决方案中。所以我们希望另一个数组具有最小可能的最大元素。 这就是这个算法的作用。

答案 2 :(得分:-1)

这个问题的逻辑是 对于K = 1,最低偏差将是最大值(假设在V1中找到)+另一个向量的第二大值(称为V2)

我已经在下面给出了如何做的方法

对于K = 1,你交换1,现在你得到两个新的向量,你再次计算K = 1,这意味着如果你知道如何得到k = 1的最小偏差,你可以重复相同的步骤k次,所以下面我给出了找到最小偏斜的步骤---&gt;

有两个向量V1和V2

步骤1 - &gt;找到所有的最大元素,假设它在V1

步骤2 - &gt;找到另一个向量的第二大元素,即在这种情况下(V2的第二大元素),假设它的名字是e2

步骤3 - &gt;找到最大的V2,假设其名称为e1

步骤4 - &gt;最大的V2,即e1的元素为V1(其中V1的元素小于e2)

以上步骤适用于k = 1 如果你重复这些步骤,你可以有最低的倾斜

E.g。有问题 - &gt;

V1 - &gt; 1 14 2 3 10 4

V2 ---&GT; 5 1 3 5 2 7

找到最大的 - &gt; V1中的14个

导致最大元素在V1中,因此找到第二大的V2 - &gt;它的5

找到最大的V2 ---&gt;它的7

将V1的3与V1中的3(其小于5)交换

计算偏斜

重复步骤