通过交换元素使数组相同

To make array identical by swapping elements

本文关键字:数组 元素 交换      更新时间:2023-10-16

有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. 制作两个映射,存储i/p数组元素的频率。

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

  3. 如果元件的频率是"0";奇数";,则不可能使它们相同。

  4. 否则,从两个映射中添加总交换,并使用
    cost=最小元素*总交换查找成本

这是代码

#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: 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 )

所以,只要找出你需要做的所有交换,应用这个公式并将结果相加就可以得到答案。

@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),您应该使用多映射,这样您就可以直接比较O(n)时间复杂度中的两个阵列,就好像两个阵列的所有元素都相同一样,您可以输出:0

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

要降低交换成本,请参阅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开始。如果索引为零,而元素为零,则意味着需要进行交换,在这种情况下,在另一个数组中找到下一个最小值并交换它们。虽然有点贵,但这是我能想到的最简单的方法。例如,在您的案例中:

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,然后用2交换6,之后你可以顺利地遍历数组。最后,你穿过第二个数组,然后当你看到最后一个7时,它会在另一边寻找最小值来交换它们。。。。,这是二,注意,如果你在一边有三个二,在另一边有一个二,那么三个二很可能会去到另一边,其中两个会回来,因为我们总是在交换最小值,所以我们总是有偶数种方法可以重新排列元素。

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

这里用于计算swap的最小数量,我们将有两种情况

举一个的例子

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

案例1。交换每对wrt到min(l1,l2)=1

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

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

试着想想,如果我们按递增顺序排列第一个列表,按递减顺序排列第二个列表,那么我们可以最大限度地降低成本。

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

诀窍是,我们只需要将min(l1,l2)存储在变量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)