题目描述 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;
}