[洛谷P2091]排序(数学:置换与循环)


题目描述 Description


小A有n个物件排成一排,每个物件有它的体积V和质量M。n个物件的体积在1~n内,且各不相同,但质量可能相同。
 现在,小A需要把n个物件按体积从小到大重新排列。他的排序方式是:每次交换两个物件。这样会他会消耗的体力值为两个物件的质量和。
 小A想知道,为了将物件排序,他消耗的最少体力值是多少?


 输入输出格式 Input/output


输入格式:
 第一行,一个正整数n,表示物件的数量。
 第二行n个正整数,第i个数表示从左到右第i个物品的体积。
 第三行n个正整数,第i个数表示从左到右第i个物品的质量
输出格式:
 一个数,表示小A消耗的最小体力值


这个题太TMD坑爹了,居然放在NOIP普及组模拟赛里,厦门一中的出题人真是丧心病狂,刚开始以为是贪心,没想到居然考了置换和循环的概念。

为了使排序费用最小,我们需要先找出物品中的最小质量minM,然后找到所有包含重为minM物品的置换环,并找到置换环的长度len,用minM物品依次交换每个置换环中的元素。


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

#define MAXN 300000
#define INF 0x3f3f3f3f

using namespace std;

struct Thing
{
    int v,m,id; //id=-1表示已经归位
    bool operator<(const Thing &b)const{return v<b.v;}
}things[MAXN]; //保存物品信息的结构体数组

int n,Min;
long long int ans=0;

int min(int a,int b)
{
    if(a<b) return a;
    return b;
}

int main()
{
    int minM=INF; //最小重量作为基元素
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&things[i].v);
        things[i].id=i;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&things[i].m);
        if(things[i].m<minM)
            minM=things[i].m;
    }
    sort(things+1,things+n+1);
    for(int i=1;i<=n;i++)
    {
        if(things[i].id==-1) continue; //这个物品已经归位,则跳过
        Min=things[i].m;
        int now=things[i].id,len=0;
        things[i].id=-1;
        ans+=things[i].m;
        while(now!=i) //找循环
        {
            Min=min(Min,things[now].m);
            ans+=things[now].m;
            int tmp=things[now].id;
            things[now].id=-1;
            now=tmp;
            len++;
        }
        ans+=min(Min*(len-1),Min+(len+2)*minM);
    }
    cout<<ans<<endl;
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值