【问题标题】:To make array identical by swapping elements通过交换元素使数组相同
【发布时间】:2020-10-27 20:07:50
【问题描述】:

有 2 个 i/p 数组。当它们具有完全相同的数字时,它们是相同的。为了使它们相同,我们可以交换它们的元素。交换是有代价的。如果我们交换 a 和 b 元素,那么 cost = min(a, b)。

在制作阵列相同的同时,成本应该是最低的。
如果无法使数组相同,则打印 -1。

i/p:     
3 6 6 2  
2 7 7 3   

o/p :     
4     
   

在这里我交换了 (2,7) 和 (2,6)。所以最小成本 = 2 + 2 = 4。

逻辑:

  1. 制作 2 张地图,用于存储 i/p 数组元素的频率。

  2. 如果aMap中的元素“a”也存在于bMap中,那么我们必须考虑a = abs(aMap中的freq(a) - bMap中的freq(a))的交换次数

  3. 如果元素的频率是“奇数”,则不可能使它们相同。

  4. 否则,从两个地图中添加总交换并使用
    查找成本 成本 = 最小元素 * 总交换次数

这里是代码

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int size;
        long long int cost = 0;
        cin >> size;
        bool flag = false;
        map<long long int, int> aMap;
        map<long long int, int> bMap;
        
        // storing frequency of elements of 1st input array in map
        for( int i = 0 ; i < size; i++)
        {
            long long int no;
            cin >> no;
            aMap[no]++;
        }

        // storing frequency of elements of 2nd input array in map
        for(int i = 0 ; i < size; i++)
        {
            long long int no;
            cin >> no;
            bMap[no]++;
        }

        // fetching smallest element (i.e. 1st element) from both map
        long long int firstNo = aMap.begin()->first;
        long long int secondNo = bMap.begin()->first;
        long long int smallestNo;
       
        // finding smallest element from both maps
        if(firstNo < secondNo)
            smallestNo = firstNo;
        else
            smallestNo = secondNo;

        map<long long int, int> :: iterator itr;

        // trying to find out total number of swaps we have to perform
        int totalSwapsFromA = 0;
        int totalSwapsFromB = 0;

        // trversing a map
        for(itr = aMap.begin(); itr != aMap.end(); itr++)
        {
            // if element "a" in aMap is also present in bMap, then we have to consider
            // number of swapping = abs(freq(a) in aMap - freq(a) in bMap)
            auto newItr = bMap.find(itr->first);
            if(newItr != bMap.end())
            {
                if(itr->second >= newItr->second)
                {
                    itr->second -= newItr->second;
                    newItr->second = 0;
                }
                else
                {
                    newItr->second -= itr->second;
                    itr->second = 0;   
                }                        
            }
            // if freq is "odd" then, this input is invalid as it can not be swapped
            if(itr->second & 1 )
            {
                flag = true;
                break;
            }
            else
            {
                // if freq is even, then we need to swap only for freq(a)/ 2 times
                itr->second /= 2;

                // if swapping element is smallest element then we required 1 less swap
                if(itr->first == smallestNo && itr->second != 0)
                    totalSwapsFromA += itr->second -1;
                else
                    totalSwapsFromA += itr->second;
            }
            
        }  

        // traversing bMap to check whether there any number is present which is 
        // not in aMap.
      if(!flag)
      {
        for(itr = bMap.begin(); itr != bMap.end(); itr++)
        {
            auto newItr = aMap.find(itr->first);
            if( newItr == aMap.end())
            {
                // if frew is odd , then i/p is invalid
                if(itr->second & 1)
                {
                    flag = true;
                    break;
                }
                else
                {
                    itr->second /= 2;

                    // if swapping element is smallest element then we required 1 less swap
                    if(itr->first == smallestNo && itr->second != 0)
                        totalSwapsFromB += itr->second -1;
                    else
                        totalSwapsFromB += itr->second;
                    
                }
                
            }
        } 
     }
       if( !flag )
       {   
          cost = smallestNo * (totalSwapsFromB + totalSwapsFromA);
          cout<<"cost "<<cost <<endl;
       }
       else
           cout<<"-1"<<endl;
    }
    return 0;
}
    

上面的代码没有错误,但是给出了错误的答案并且没有被接受。
任何人都可以改进此代码/逻辑吗?

【问题讨论】:

  • 不要使用可变长度数组,a[size]andn[size]aHash[N]bHash[N],即使你的编译器接受它们(如 g++),使用的大小至少因为 N 值是可能超出堆栈的大小
  • 奇怪的是,就在昨天我们还有Making Two Arrays Identical by swapping elements [closed] :)
  • 正确的解决方案是交换(6, 7),所以成本是1。我不知道你的代码为什么这么复杂。我认为它在 20 行内是可行的。
  • aHash[a[i]] 中,你怎么能认为a[i]cin &gt;&gt; a[i]; 之后的aHash 中的有效索引? bHash[b[i]]中的相同
  • @MarekR 如果我们交换(6,7),那么成本将为 6。(成本 = min(交换元素 a,b))

标签: c++ algorithm c++11


【解决方案1】:

问题链接https://www.codechef.com/JULY20B/problems/CHFNSWPS

这里用于计算交换的最小数量。我们将有 2 个案例

举个例子

l1=[1,2,2]
l2=[1,5,5]

案例 1. 将每一对 wrt 交换为 min(l1,l2)=1

步骤 1 从 l1-> [1,1,2] 交换一对 2 中的单个 2 [2,5,5] 成本为 1
第 2 步从 l1-> [1,5,2] 交换一对 5 中的单个 5 [2,1,5] 成本为 1
总成本为 2

案例 2. 将 l1 的最小值与 l2 的最大值交换(重复直到两个列表结束)

尝试考虑如果我们按升序对第一个列表进行排序,而按降序对其他列表进行排序,那么我们可以最大限度地降低成本。

 l1=[1,2,2]
 l2=[5,5,1]

诀窍是我们只需要将 min(l1,l2) 存储在变量 say mn 中。然后从两个列表中删除所有公共元素。

now list became l1=[2,2]
                l2=[5,5]

然后将每个元素从索引 0 交换到 len(l1)-1,跳跃为 2,例如 0,2,4,6..... 因为每个奇数邻居都将与前一个数字相同。 执行交换成本后将是 2 和

l1=[5,2]
l2=[2,5]  cost is 2
total cost is 2

再说一个例子

l1=[2,2,5,5]
l2=[3,3,4,4]

将 wrt 求解为 min(l1,l2) 后,总成本将为 2+2+2=6
但排序列表后的成本将是 ((2,4) 和 (5,3)) 的交换是 2+3=5
所以使列表相同的最小交换是 min(5,6)=5

    //code 
    l1.sort()
    l2.sort(reverse=True)
    sums=0
    for i in range(len(l1)):
            sums+=min(min(l1[i],l2[i]),2*minimum))
    print(sums)
    #print -1 if u get odd count of a key in total (means sums of count of key in both list)

【讨论】:

  • 虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案添加解释并说明适用的限制和假设。
【解决方案2】:

要降低交换成本,请参阅 Daniel 的回答。要确定交换是否真的可能,请执行以下操作,实际上只有当您总共有偶数个元素时才能进行交换,这样您就可以将它们平均拆分,所以如果您有 2、4 或 6 个 5你很好,但如果你有 1、3 或 5 5 的回报 -1。如果您的数字重复数是奇数,这是不可能的。为了实际解决这个问题,我能想到一个非常简单的解决方案,虽然它有点贵,你只需要确保每一边都有相同数量的元素,所以简单的方法就是是要声明一个新数组:

int temp[size of original arrays];
//Go through both arrays and store them in temp

取每个元素的一半,比如:

int count[max element in array - min element in array];
for(int i = 0; i < temp.size(); i++){
   count[temp[i]]++;
}

从 temp 中取出每个元素的一半。当您看到与 count 数组中的元素匹配的元素时,每当您看到 1 时,count 数组上的索引就会减 1,因此类似于 count[1]--;假设计数从 0 开始。如果索引为 0 且元素为 1,则意味着需要进行交换,在这种情况下,在另一个数组中找到下一个最小值并交换它们。虽然有点贵,但这是我能想到的最简单的方法。因此,例如在您的情况下:

i/p:     
3 6 6 2  
2 7 7 3   

o/p :     
4   

我们需要将最小索引存储为 2。因为这是最小的索引。所以我们会有一个如下所示的数组:

1 1 0 0 1 1
//one two one three zero four zero five 1 six and 1 seven

你会遍历第一个数组,当你看到第二个 6 时,你在 6 处的数组索引将为零,所以你知道你需要交换它,你会在另一个数组中找到最小值,即 2 和然后将 6 与 2 交换,之后您可以顺利通过阵列。最后你通过第二个数组,然后当你看到最后一个 7 时,它会在另一侧寻找 min 交换它们....,这是两个,请注意,如果你在一侧有 3 个二,在一侧有一个二另一个,很可能三个二会去另一边,其中两个会回来,因为我们总是交换最小值,所以我们总是有偶数种方法可以重新排列元素。

【讨论】:

    【解决方案3】:

    @user1745866 您可以通过仅使用变量来简化确定答案 -1 的任务:

    让我们有 int x=0,我们将像这样对所有 i/p 整数进行 XOR

    int x = 0;
    for(int i=0;i<n;i++){
      cin>>a[i];
      x = x^a[i];
    }
    for(int i=0;i<n;i++){
      cin>>b[i];
      x = x^b[i];
    }
    
    if(x!=0)
      cout<<-1;
    else{
      ...do code for remain 2 condition...
    }
    

    现在的重点是它将如何工作,因为两个数组的所有数字都应该只出现偶数次,当我们对任何出现偶数次的数字进行 XOR 操作时,我们将得到 0.... 否则它们不能是相同的数组。

    现在对于第二个条件(给出答案 0),您应该使用 multimap,这样您就可以在 O(n) 时间复杂度内直接比较两个数组,就好像两个数组的所有元素都相同,您可以输出: 0

    注意:我建议使用多映射,因为 1:您将对数组进行排序,并且所有元素都将存在也意味着重复。
    2:因为它们是排序的,如果它们在相同的位置由相同的元素组成,我们可以输出:0 否则你必须进一步处理你的第三个条件或者必须交换元素。)

    【讨论】:

      【解决方案4】:

      假设你有 2 个数组:

      A: 1 5 5
      B: 1 4 4
      

      我们知道我们想将 5 向下和 4 向上移动,所以我们必须选择:用 5 交换 4(成本 min(4, 5) = 4)或使用最小元素来实现相同的结果,进行 2 次交换:

      A: 1 5 5   swap 1 by 4 (cost 1)
      B: 1 4 4    
      ________
      A: 4 5 5   swap 1 by 5 (cost 1)
      B: 1 1 4
      ________
      A: 4 1 5   total cost: 2
      B: 5 1 4    
      

      所以我们在每次交换时都会做的问题是这样的。是直接交换还是以最小元素为轴交换两次更好?

      简而言之,让m 成为两个数组中的最小元素,并且您想将i 交换为j。交换的成本将是

      min( min(i,j), 2 * m )
      

      因此,只需找出您需要进行的所有交换,应用此公式并将结果相加即可得到答案。

      【讨论】:

      • 我已经更新了代码,并按照你说的做了。但仍然给我错误的答案并且没有被接受。我错过了任何角落案例吗? (代码没有错误,并为我的输入提供正确的答案。)
      • 您确定要交换尽可能少的元素吗?您确定您正确处理了无法解决的情况(即出现奇数次的数字)?
      猜你喜欢
      • 2013-07-22
      • 1970-01-01
      • 1970-01-01
      • 2021-11-23
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多