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

Swapping values between two vectors so that sum of max_elements of two vectors is minimum

本文关键字:两个 向量 elements max 之间 交换      更新时间:2023-10-16

这是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我先把V1的9换成V2的4。这给了:

V1 = 5 6 7 4

V2 = 9 10 5 9

与之前的19相比,最高的数之和为17。我可以做的第二次交换是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。所以即使当前的安排是最好的,它仍然会交换一些值。早些时候,当目前的安排是最好的时候,我打破了。这样做的原因是因为除了两个之外,我所有的测试用例都是正确的!猜猜更烦人的是什么,每个任务都有一个!:(所以我意识到必须完成所有K开关。然而,即使现在我得到了2个错误的测试用例,一定有什么我忽略了。

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

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

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

你还做了大量的向量复制,这使得代码效率低下。即使你的代码逻辑是正确的,你的代码也不会通过时间限制,因为你的方法是0 (n2)。


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

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

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

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;
}

如果我理解正确,您希望最小化两个最大元素的总和,每个数组一个。你只能做K次交换。

假设数组是排序的(这不会改变算法)。选择k元素顺序较小的数组。我们称这个数组为S,另一个为B。在每次交换中,从数组S中取出最大的元素,并与数组B中最小的元素交换。如果在某一时刻数组S中的所有元素都小于数组B中的元素,则停止。

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

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

我已经给出了做这件事的方法

对于K=1,你把它们换成1,现在你得到了两个新的向量,你再次计算K=1,这意味着如果你知道如何得到K=1的最小偏度,你可以重复同样的步骤K次,所以下面我给出了找到最小偏度的步骤->

有两个向量V1和V2

步骤1 ->找到所有元素中最大的元素,假设它在V1

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

步骤3 ->找到最大的V2假设它的名字是e1

step4 ->用V1的一个元素(V1的元素小于e2)交换最大的V2即e1

以上步骤是针对k=1如果你重复这些步骤,你可以得到最小的倾斜

。给定问题——>

V1 -> 1 14 2 3 10 4

V2-> 5 1 3 5 2 7

在V1

中找到最大的——>它的14

因为最大的元素在V1中,所以找到V2的第二大元素->它的5

找到最大的V2——>它的7

交换V2的7和V1的3(小于5)

计算斜度

重复步骤