neu 1493 Caoshen like math(最小交换次数)

http://acm.neu.edu.cn/hustoj/problem.php?cid=1047&pid=4

题意:数字1到n 任意排列

求排列成有序序列最少交换次数

思路:求最小交换次数有两种

1 交换的两数必须相邻  (poj 2299)

通过归并排序求出其逆序数即为所求值

证明:可以先将最大数交换到最后,由于是相邻两个数交换,需要交换的次数为最大数后面的数的个数(可以看做是最大数的逆序数),然后,交换过后,去除最大数,再考虑当前最大数也需要其逆序数次交换。则每个数都需要交换其逆序数次操作,则总最少交换次数为序列总体的逆序数。

2 交换任意两数

也就是此题

这题有两种方法

1 第一种是每次将排完序后当前位置的值与现在当前位置的值交换 求出即为最小交换数

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int   a[1000000+10];
int vis[1000000+10];
int ans;
void swap(int &a,int &b)
{
    int temp=a;
    a=b;
    b=temp;
}
int main()
{
    int n;
    int i,j,k;
    while(scanf("%d",&n)!=EOF)
    {
        ans=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            vis[a[i]]=i;
        }
        for(i=1;i<=n;i++)
        {
            int temp=a[i];
            if(a[i]!=i)
            {
                ans++;
                vis[temp]=vis[i];
                swap(a[i],a[vis[i]]);

            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

2 求出循环节个数 ans= n-循环节个数(根据之前的坐标和排序之后的坐标,构建成一个有向图)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int num[1000000+10][2];
int main()
{
    int n;
    int i,j,k;
    while(scanf("%d",&n)!=EOF)
    {
        int to;
        int ans=0;//环的个数
        memset(num,0,sizeof(num));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&to);
            num[i][1]=1;
            num[to][0]=1;
            if(num[to][1]==1) ans++;
        }
        printf("%d\n",n-ans);
    }
    return 0;
}
时间: 2024-10-15 10:51:08

neu 1493 Caoshen like math(最小交换次数)的相关文章

关于一个求最小交换次数的算法的一个严格证明,是严格证明,不是想当然

问题描述: 有一个1~n的数列的排列,但是这个数列已经被打乱了排列顺序,如果我们只是通过"交换任意两个元素",那么,要实现元素从1~n的有序排列,"最少的交换次数是多少?" 解答过程: 首先我们纸上可以先写写简单的情况试试,比如排列:4 3 1 2, 交换次数=3:我们可以在多组测试中,边测试边想,真正的实现需要满足:4本该到2处, 2本该到3处, 3本该到1处, 1本该到4处,刚好一个循环. 于是,考虑: 引理:是否对于满足这种一个循环的排列,最少交换次数等于元素

Cycle Sort (交换次数最少的排序)

该算法的效率并不高.但是却提供了一个很好的思路.如何让一个序列在最小交换次数下实现有序. Cycle Sort 翻译成中文是 圈排序. 这个圈在于需要交换的数据形成圈. 具体一点: 如: Array  4 3 2 5 5 6  要处理的数组 Result 2 3 4 5 5 6  结果 pos     0 1 2 3 4 5  下标 从下标0的元素开始观察.4 需要到下标 2 而下标2的元素为 2 需要到下标0 .刚好可以回到4. 也就是形成了 4-2 这样的圈 接下来是3 需要到下标1 而3本

使序列递增的最小交换

我们有两个长度相等且不为空的整型数组 A 和 B . 我们可以交换 A[i] 和 B[i] 的元素.注意这两个元素在各自的序列中应该处于相同的位置. 在交换过一些元素之后,数组 A 和 B 都应该是严格递增的(数组严格递增的条件仅为A[0] < A[1] < A[2] < … < A[A.length - 1]). 给定数组 A 和 B ,请返回使得两个数组均保持严格递增状态的最小交换次数.假设给定的输入总是有效的. 示例: 输入: A = [1,3,5,4], B = [1,2,

【算法28】冒泡排序中的交换次数问题

问题描述 题目来源:Topcoder SRM 627 Div2 BubbleSortWithReversals 给定待排序数组A,在最多反转K个A的不相交子数组后,对A采用冒泡排序,问最小的swap次数是多少?冒泡排序的伪代码如下: BubbleSort(A): 循环len(A) - 1次: for i from 0 to len(A) - 2: if (A[i] > A[i+1]) swap(A[i], A[i+1]) 问题分析 首先,容易分析得到:对于任意待排序数组A,其采用冒泡排序所需要的

453. 最小移动次数使数组元素相等

给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数.每次移动可以使 n - 1 个元素增加 1. 示例: 输入: [1,2,3] 输出: 3 解释: 只需要3次移动(注意每次移动会增加两个元素的值): [1,2,3] => [2,3,3] => [3,4,3] => [4,4,4] 思路: 设加x次,加到最后,每个数都为y sum:数组元素的和 min:数组中最小的元素 n:数组中元素的个数 则有: sum+(n-1)*x = n*y(式1) y = min+x(式

NYOJ 46 最小乘法次数

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=46 用类似于快速幂的方法做,注意1的时候是0: #include <iostream> using namespace std; int main() { int ase; int num; int res; cin>>num; while(num--) { res = 0; cin>>ase; if(ase==1) { cout<<0<<

UPC 2959: Caoshen like math 这就是个水题

http://acm.upc.edu.cn/problem.php?id=2959 这就是个水题,之所以要写这个题是感觉很有纪念意义 用力看就是盲……23333333333333333 这个题就是最小交换几次使数组有序,首先想到的竟然是逆序数 但是逆序数是冒泡排序用的,怎么可能最小……!!!! 具体题解是: 先用结构体标记每个元素的位置和内容,然后进行排序 跟原来的数组进行比较,位置不符合,将原数组 元素 跟 本该排好序在这个位置的元素交换 然后 二分查找 结构体数组里面 该 元素 将 坐标更新

冒泡排序的交换次数

题意: 给定一个1~n的排列a0,a1,-an-1,求对这个数列进行冒泡排序所需要的交换次数(冒泡排序是每次找到满足ai>ai+1的i,并交换ai和ai+1,直到这样的i不存在为止的算法). 限制条件:1<= n<= 100000 输入: n=4, a={3,1,4,2} 输出: 3 冒泡排序的复杂度是O(n2),所有无法通过模拟冒泡排序的过程来计算需要的交换次数.不过我们可以通过选取适当的数据结构来解决这个问题. 首先,所求的交换次数等价于满足i<j,ai>aj的(i,j)

POJ 2299-Ultra-QuickSort(归并排序求相邻元素的交换次数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 43816   Accepted: 15979 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin