[ACM] POJ 3270 Cow Sorting (置换,贪心)

286 篇文章 140 订阅
41 篇文章 0 订阅

Cow Sorting
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 5946 Accepted: 2263

Description

Farmer John's N (1 ≤ N ≤ 10,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" level in the range 1...100,000. Since grumpy cows are more likely to damage FJ's milking equipment, FJ would like to reorder the cows in line so they are lined up in increasing order of grumpiness. During this process, the places of any two cows (not necessarily adjacent) can be interchanged. Since grumpy cows are harder to move, it takes FJ a total of X+Y units of time to exchange two cows whose grumpiness levels are X and Y.

Please help FJ calculate the minimal time required to reorder the cows.

Input

Line 1: A single integer:  N
Lines 2.. N+1: Each line contains a single integer: line  i+1 describes the grumpiness of cow  i

Output

Line 1: A single line with the minimal time required to reorder the cows in increasing order of grumpiness.

Sample Input

3
2
3
1

Sample Output

7

Hint

2 3 1 : Initial order. 
2 1 3 : After interchanging cows with grumpiness 3 and 1 (time=1+3=4). 
1 2 3 : After interchanging cows with grumpiness 1 and 2 (time=2+1=3).

Source


解题思路:

题意为给定N只牛,每只牛都有自己的坏脾气值,现在要把这N只牛按照坏脾气值从小到大排序,每一次交换的代价定义为被交换的两头牛的坏脾气值之和,问最小的代价是多少。

刘汝佳黑书上的例题(P247 无聊的排序是和这个一样的)。下面是书上作者给的解题思路,用到了贪心和置换的知识,很好懂:


输入的数原来的位置是按输入顺序,1,2,3,4.n的,排完序后用pos[]数组记下这些数新的位置,然后再找循环节,每一个循环节都进行上面说的两种操作,取最小值,结果累加。


代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=100010;
int val[maxn];
int temp[maxn];//备用数组,排序前
int pos[maxn];//排序后的位置
bool vis[maxn];//找循环节看是否被访问过。
int MIN=0x7fffffff;//全局最小值
int Min;//每个循环节的最小值
int n;//牛的头数
int ans=0;

int main()
{
    memset(vis,0,sizeof(vis));
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        temp[i]=val[i];
        if(MIN>val[i])
            MIN=val[i];
    }
    sort(val+1,val+1+n);
    for(int i=1;i<=n;i++)
        pos[val[i]]=i;//排序后各元素所在的位置
    //找循环节
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            int cnt=0;//循环节的长度
            int label=i;//循环节里面的元素,label始终代表原始输入的时候是第几个数。
            int sum=0;//循环节里面元素和
            Min=temp[label];
            while(!vis[label])
            {
                vis[label]=1;
                cnt++;
                Min=min(Min,temp[label]);
                sum+=temp[label];
                label=pos[temp[label]];
            }
            ans+=(sum+min((cnt-2)*Min,Min+(cnt+1)*MIN));
        }
    }
    cout<<ans;
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值