求最小交换次数

求最小交换次数

  1. 相邻交换
  2. 任意交换

相邻交换:(求逆序对数)

  1. 归并排序
void msort(vector<int> &a, int l, int r) {
    if (l == r) {
        return;
    }
    int m = (l + r) >> 1;
    msort(a, l, m);
    msort(a, m + 1, r);
    tmp.clear();
    for (int i = l, j = m + 1; i <= m || j <= r;) {
        if (i <= m && j <= r) {
            if (a[i] <= a[j]) {
                tmp.push_back(a[i]);
                i++;
            } else {
                tmp.push_back(a[j]);
                j++;
                res += (m - i + 1); //
            }
        } else if (i <= m) {
            tmp.push_back(a[i]);
            i++;
        } else {
            tmp.push_back(a[j]);
            j++;
        }
    }
    for (int i = 0; i < tmp.size(); i++) {
        a[l + i] = tmp[i];
    }
}
  1. 树状数组
#include<bits/stdc++.h>
#define M 500005
using namespace std;
int a[M],d[M],t[M],n;
int lowbit(int x)
{
	return x&-x;
}
int add(int x)//把包含这个数的结点都更新 
{
	while(x<=n)//范围 
	{
		t[x]++;
		x+=lowbit(x);
	}
}
int sum(int x)//查询1~X有几个数加进去了 
{
	int res=0;
	while(x>=1)
	{	
		res+=t[x];
		x-=lowbit(x);
	}
	return res;
}
bool cmp(int x,int y)//离散化比较函数 
{
	if(a[x]==a[y]) return x>y;//避免元素相同 
	return a[x]>a[y];//按照原序列第几大排列 
}
int main()//402002139
{
	//freopen("in.txt","r",stdin);
	long long ans=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i],d[i]=i;
	sort(d+1,d+n+1,cmp);//离散化 
	for(int i=1;i<=n;i++)
	{
		add(d[i]);//把这个数放进去 
		ans+=sum(d[i]-1);//累加 
	}
	cout<<ans;
	return 0;
}

任意交换:(求置换环数)

  • 离散化+ (找环/并查集)
int judge(vector<int> &a) {
        int n = a.size();
        vector<int> b = a;
        sort(b.begin(), b.end());
        for (int i = 0; i < n; i++) {
            a[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
        }
        int res = n;
        vector<bool> vis(n);
        for (int i = 0; i < n; i++) {
            if (vis[i]) continue;
            int j = i;
            while (!vis[j]) {
                vis[j] = 1;
                j = a[j];
            }
            res--;
        }
        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值