zoukankan      html  css  js  c++  java
  • [POJ 3270]Cow Sorting

    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).

    题目大意:

    给你一个排列,然后让你交换到递增排列,交换X和Y的位置,花费就是X+Y,求变成递增序列的最小花费

    题解:

    我们先说说样例:2 3 1 —— ①

    编号分别为:       1 2 3 —— ②

    排序后的编号为:3 1 2 —— ③

    这样一来我们就可以理解为②经过一系列变换就形成了③(也就是最终形态),那么既然是序列变换,我们考虑置换。那么②和③形成了一个置换。

    $$inom{1,2,3}{3,1,2}$$

    那么对于一个置换,我们分别处理置换上的每一个环,有两点可以肯定:

      1.一个环可以通过自身内部的交换形成最终形态。

      2.当每一个环都形成了最终形态时,序列也就从②变到了三③。

    那么接下来怎么求出代价的最小值呢?


    首先我们分别考虑每一个环,如果不考虑其他环对这个环的影响(也就是说,这个环在自己内部交换)。

    此时有一个贪心十分显然,用一个环的最小值去和环上的每一个数分别交换所付出的代价最小。

    下面我们给出证明:

      假设我们当前处理的环长度为$k$,那么我们必定要交换$k-1$次。(不可能更多,因为环已经确定了每一个数的先后关系,我们只要两两之间分别交换就好)

      ∴我们要在环上确定一个起点$x$,这个$x$沿着环交换一圈即可。

      ∴付出的代价为$sum-v[x]+v[x]*(tot-1)$(sum为环上权值和,tot为环上的点数,v[x]为起点的权值)

      ∴权值越小越好。

      综上所述,得证。

    接下来我们考虑其他环的影响。


    假设某一个环上的最小值比当前处理的环的最小值还要小,那么我们只要将这两个环的最小值先交换,然后处理完当前环,在交换回去。

    那么这样做的代价和单独考虑一个环的代价取个最小值,就是处理完这个环的代价。

    于是乎我们只要求出所有数中的最小值min,再将它代入每一个环求一遍,然后和这个环自身处理的代价比较一下就好。

     1 //Never forget why you start
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<cmath>
     7 #include<algorithm>
     8 #define inf (2147483647)
     9 using namespace std;
    10 int n,m,ans;
    11 struct node{
    12   int x,id,pos;
    13   friend bool operator < (const node a,const node b){
    14     return a.x<b.x;
    15   }
    16 }a[10005];
    17 bool cmp(const node a,const node b){
    18   return a.id<b.id;
    19 }
    20 struct part{
    21   int mmin,sum,tot;
    22   part(){}
    23   part(int _mmin,int _sum,int _tot){
    24     mmin=_mmin;
    25     sum=_sum;
    26     tot=_tot;
    27   }
    28 }o[10005];
    29 int vis[10005],cnt,mmin[10005],sum[10005],tot[10005],tmp,p,lm;
    30 void dfs(int r){
    31   vis[r]=1;
    32   p+=a[r].x;
    33   cnt++;
    34   tmp=min(tmp,a[r].x);
    35   if(vis[a[r].pos]==1){mmin[r]=tmp;sum[r]=cnt;tot[r]=p;return;}
    36   else dfs(a[r].pos);
    37   tot[r]=p;
    38   mmin[r]=tmp;
    39   sum[r]=cnt;
    40 }
    41 int main(){
    42   int i,j;
    43   while(scanf("%d",&n)!=EOF){
    44     memset(mmin,0,sizeof(mmin));
    45     memset(vis,0,sizeof(vis));
    46     memset(a,0,sizeof(a));
    47     memset(o,0,sizeof(o));
    48     memset(sum,0,sizeof(sum));
    49     memset(tot,0,sizeof(tot));
    50     lm=0;ans=0;
    51     for(i=1;i<=n;i++){
    52       scanf("%d",&a[i].x);
    53       a[i].id=i;
    54     }
    55     sort(a+1,a+n+1);
    56     for(i=1;i<=n;i++)a[i].pos=i;
    57     sort(a+1,a+n+1,cmp);
    58     for(i=1;i<=n;i++)
    59       if(!vis[i]){
    60     cnt=0;
    61     p=0;
    62     tmp=inf;
    63     dfs(i);
    64     o[++lm]=part(mmin[i],sum[i],tot[i]);
    65       }
    66     tmp=inf;
    67     for(i=1;i<=lm;i++)tmp=min(tmp,o[i].mmin);
    68     for(i=1;i<=lm;i++){
    69       ans+=min(2*(tmp+o[i].mmin)+(o[i].sum-1)*tmp+o[i].tot-o[i].mmin,o[i].tot-o[i].mmin+(o[i].sum-1)*o[i].mmin);
    70     }
    71     printf("%d
    ",ans);
    72   }
    73   return 0;
    74 }
  • 相关阅读:
    第二次刷题感受——路漫漫其修远兮,吾将上下而求索。
    刷题就是照镜子——第一次刷2008年初赛题感受
    第一次集训刷题感受
    我的第一个博客
    预测房价的回归问题
    电影评论的情感极性分析
    语音助手是这样子的(二)
    语音助手是这样子的(一)
    软工第一次作业
    2020软件工程第五次作业_第二组
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/8343431.html
Copyright © 2011-2022 走看看