POJ 3270 Cow Sorting(置换)

来源:互联网 发布:java替换\ 编辑:程序博客网 时间:2024/06/08 04:06

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

3231

Sample Output

7

题目大意

有N头牛,每头牛都有自己的愤怒值(各不相同),现在John通过交换牛的位置(可以不相邻)使它们的愤怒值从小到大排序,每交换一次的代价是两头牛的愤怒值之和。求最小的代价值。

解题思路

初始数据有多少个循环节就有多少个无序的子序列,我们只需要使得每个子序列局部有序则整体便可达到有序的目的。而在任一循环节中进行交换时,为了使最终代价值最小,则尽量使交换次数越小,每次交换的两个数越小。通过分析,我们有两种方案可供选择:
1、在每一个循环节中选取一个最小的值minn,然后该循环节的其他数分别与minn进行交换实现排序。很容易发现除了minn其它数都只是交换了一次,而minn值交换了(k-1)次,则代价值可以表示为 sum-minn+(k-1)*minn(其中sun是当前循环节所有数的和,k是循环节的长度);
2、对当前循环节而言,可以先将当前循环节的最小值minn与所有数的最小值minx进行交换,然后用minx代替minn依次与循环节中的其他元素进行交换,到最后minn值与minx再交换一次归位,在此过程中 minx只是起到一个中介的作用,尽可能减小在与循环节其他元素交换的代价值。则代价值可以表示为(minn+minx)+(sum-minn)+(k-1)*minx+(minn+minx)=sum+minn+(k+1)*minx。
对于以上两种情况,无法确定那个选择会更好一点,所以在求解过程中分别计算选取较小值。

代码实现

#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;#define maxn 100007int a[maxn],b[maxn],c[maxn],vis[maxn],num[maxn],minn[maxn],sum[maxn];int countt,temp,n;void handle(){    memset(vis,0,sizeof(vis));    memset(num,0,sizeof(num));    memset(minn,0x3f,sizeof(minn));    memset(sum,0,sizeof(sum));    countt=0;    for(int i=1; i<=n; i++)    {        if(!vis[b[i]])        {            vis[b[i]]=1;            temp=a[b[i]];            minn[countt]=min(minn[countt],temp);            sum[countt]+=temp;            num[countt]++;            while(!vis[temp])            {                vis[temp]=1;                temp=a[temp];                minn[countt]=min(minn[countt],temp);                sum[countt]+=temp;                num[countt]++;            }            countt++;        }    }}int main(){    while(~scanf("%d",&n))    {        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        memset(c,0,sizeof(c));        int ans=0;        int minx=100007;        for(int i=1; i<=n; i++)        {            scanf("%d",&a[i]);            b[i]=a[i];            c[i]=a[i];            minx=min(minx,a[i]);        }        sort(b+1,b+n+1);        for(int i=1; i<=n; i++)            a[b[i]]=c[i];        handle();        for(int i=0; i<countt; i++)        {            ans+=(sum[i]+min((num[i]-2)*minn[i],minn[i]+(num[i]+1)*minx));        }        printf("%d\n",ans);    }    return 0;}

PS:愤怒值数据并不是1~n,贡献一次WA

原创粉丝点击