序列排序

洛谷题目链接:序列排序

题目描述

小C有一个N个数的整数序列,这个序列的中的数两两不同。小C每次可以交换序列中的任意两个数,代价为这两个数之和。小C希望将整个序列升序排序,问小C需要的最小代价是多少?

输入输出格式

输入格式:

第一行,一个整数N。

第二行,N个整数,表示小C的序列。

输出格式:

一行,一个整数,表示小C需要的最小代价。

输入输出样例

输入样例#1:

6
8 4 5 3 2 7

输出样例#1:

34

说明

数据范围:

对于30%的数据,1<=N<=10;

对于全部的数据,1<=N<=100000,输入数据中的其他整数均为正整数且不超过109。

简述一下题意:给出一个长度为n的序列(其中元素权值各不相同),通过多次交换两个元素使得整个序列为升序.每次交换的代价是交换的两个元素的权值,要求出最小的代价.

简单想一下,因为每个权值都不同,那么很显然我们是知道最终状态是怎么样的,那么很显然不论怎么样交换,每个元素都有一个它最终要到的位置.

既然这样,那么我们可以处理出每个元素最终要到的位置,以这样方式交换那么序列中的交换情况就可以看作是几个环.

现在假设有这样一个序列:3 1 2 5 4.它的最优交换方法为swap(1 , 2),swap(1 , 3),swap(4 , 5).1要到第一位,2要到第2位,3要到第3位,很显然1,2,3这三个下标上的数组成了一个交换的环,也就是从一个位置出发一直找该下标元素最终要到的位置,然后再从这个位置出发直到走到一开始出发的那个位置.(我们接下来讲的环都是指这个概念),那么在环上交换的贪心策略很显然是用最小的值与其他值来交换.

那么显然可以得到这样一个贪心:

找到一个交换的环中最小的权值,用它来与在这个环上的其他未归位的元素交换.

但是这样的贪心仍然是有问题的.我们看这样一组数据:

5
1 60 30 40 50

如果只考虑用换上的最小值来交换的话,求出来的答案是240,但是如果先将环上最小值和整个序列上的最小值进行交换,然后用这个最小值来代替之前的最小值来计算,就有可能得到更优解.

于是得到一个优化后的贪心策略:判断是使用当前交换环上最小值来完成交换还是先将环上最小值与整个序列最小值交换得到的结果更优.

然后就是注意一下找环的时候一些边界问题,注意一下细节就没了.

#include<bits/stdc++.h>
using namespace std;
typedef long long lol;
const int N=100000+5;
const int inf=2147483647;

lol n, ans = 0, w[N];
lol len = 0, tot = 0;
lol mn = inf, minn = inf;

struct brick{
    lol id, w;
}a[N];

bool cmp(brick a,brick b){
    return a.w < b.w;
}

int main(){
    cin >> n;
    for(lol i=1;i<=n;i++){
        cin >> a[i].w;
    a[i].id = i; w[i] = a[i].w;
        minn = min(minn , a[i].w);
    }
    sort(a+1 , a+n+1 , cmp);
    for(lol i=1;i<=n;i++){
    if(a[i].id != i){
        lol k = a[i].id; tot = w[i]; len = 1;
        a[i].id = i; mn = w[i];
        while(k!=i){//找环
        len++; mn = min(mn , w[k]);
        tot += w[k];
        swap(a[k].id , k);
        }
        if(mn == minn) ans += tot+mn*(len-2);
        else ans += min(minn*(len+1)+mn+tot,tot+mn*(len-2));//判断哪种情况更优
    }
    }
    cout << ans << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/BCOI/p/8878073.html

时间: 2024-10-11 10:50:03

序列排序的相关文章

洛谷P2127 序列排序 [贪心]

题目传送门 题目描述 小C有一个N个数的整数序列,这个序列的中的数两两不同.小C每次可以交换序列中的任意两个数,代价为这两个数之和.小C希望将整个序列升序排序,问小C需要的最小代价是多少? 输入输出格式 输入格式: 第一行,一个整数N. 第二行,N个整数,表示小C的序列. 输出格式: 一行,一个整数,表示小C需要的最小代价. 输入输出样例 输入样例#1: 复制 6 8 4 5 3 2 7 输出样例#1: 复制 34 说明 数据范围: 对于30%的数据,1<=N<=10: 对于全部的数据,1&l

【Excel】将IP按照IP地址(v4)增长序列排序

Background: Excel列中,有多个net-block, 将这些net-block按照IP地址(v4)自己的大小从小到大排序. Idea: IPv4地址的格式是点分十进制的,也就是说每一个点前的数字都有自己相应的power权值,只要找到这个权值,再将IP地址以“."分开,分别乘以其权值,就可以得到某个IP唯一对应的一个反应其真实大小的十进制值. Solution: 以下面这几个IP block为例,D2 到 G2是为了去find一个IP网段这种格式中的“.”和“/”,具体的语句,以D2

Baidu笔试-01序列排序的交换次数

问题描述: 问题分析: 解法一:设置双指针,start,end;当data[start]='1',data[end]='0'时,表示需要进行交换,次数加1:否则data[end]='1'则前移end指针:data[start]='0'则后移start指针: 该算法仅需遍历一次 解法二:先遍历一次计算字符数组中0的个数zero,再计算前zero个字符中1的个数,即是要交换到后面的字符(仅需遍历到zero个字符即可): 代码: 解法一: import java.util.Scanner; publi

【西北大学2019新生赛】序列排序II

原题: 想了很久,想的是模仿冒泡,从大到小检查每一个数后面的数是否都与它互质,然后把它设为1(等价于放到最后不考虑) 然后一直想数据结垢 出来跟人交流,“这不是挺典型的思维题么哈哈哈” 利用性质: 调和级数求和,当n=1e5时n/1+n/2+...+n/n约等于1e7 这个性质至少是第二次见了,拿个小本子记下来 或者说需要注意到性质: 小于等于n的数中是k的倍数的数有n/k个 看上去非常简单但是好像还挺容易被我忽略的哈哈 方式方法: 枚举gcd 涉及到整除互质之类的,枚举gcd好像也非常常见 所

python sort、sorted高级排序技巧

Python list内置sort()方法用来排序,也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列. 1)排序基础 简单的升序排序是非常容易的.只需要调用sorted()方法.它返回一个新的list,新的list的元素基于小于运算符(__lt__)来排序. 复制代码 代码如下: >>> sorted([5, 2, 3, 1, 4]) [1, 2, 3, 4, 5] 你也可以使用list.sort()方法来排序,此时list本身将被修改.通常此方法不如s

数据结构6种内部排序算法的比较

1.需求分析 (1)输入数据的形式为:伪随机数产生程序产生,且每次输入数不少于100个,至少要用5组不同的输入数据 (2)输出的形式为:输出关键字参加的比较次数和关键字的移动次数(关键字交换计为3次移动)的数据 (3)程序能达到的功能:对起泡排序,直接插入排序,简单选择排序,快速排序,希尔排序,堆排序这6种常用的内部排序算法进行比较,比较的指标为有关键字参加的比较次数和关键字的移动次数(关键字交换计为3次移动) (4)测试数据:正确输入为由伪随机数产生程序产生100个随机数,然后输出比较结果,错

八大排序算法

转载:http://blog.csdn.net/hguisu/article/details/7776068 目录(?)[+] 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速

JS实现常用排序算法—经典的轮子值得再造

关于排序算法的博客何止千千万了,也不多一个轮子,那我就斗胆粗制滥造个轮子吧!下面的排序算法未作说明默认是从小到大排序. 1.快速排序2.归并排序3.冒泡排序4.选择排序(简单选择排序)5.插入排序(直接插入排序)6.希尔排序二分查找 1.快速排序 为什么把快排放在最前面呢,因为传说Chrome中数组的sort方法默认采用的就是快排. 算法思想: (1)在数据集之中,选择一个元素作为"基准"(pivot). (2)所有小于"基准"的元素,都移到"基准&quo

“《算法》第4版第2章‘排序’”:归并排序

归并排序(Merge Sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 归并操作(Merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作.归并排序算法依赖归并操作.归并排序有多路归并排序.两路归并排序 , 可用于内排序,也可以用于外排序.这里仅对内排序的两路归并方法进行讨论. 归并排序的步骤如下: 1)Divide: 将待排序序列(原问题)分成两个规模大致相等的子序列(子问题