洛谷 P2127 序列排序

https://www.luogu.org/problemnew/show/P2127

 

感觉题解里写的比较复杂,可能自己的想法比较简单一点吧。

看这个图中的的点如果形成一个环,贪心的考虑,要想花费最少,那么我们一定要多次利用最小那个点。

图中来看就是2和6交换,然后2和4交换,然后就交换完了。

然而还有一种换法就是,这个环中最小的点和序列中最小的点先交换,然后在进行环内的操作(就是说先2和1交换...)。

所以对于每个点dfs找到环,然后判断两种方法哪种更优,统计答案。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL long long
#define inf 2147483647
LL n,a[100006],b[100006],MIN,pos[100006],siz,sum,minn;
bool vis[100006];
LL ans;
void dfs(int x)
{
    if(vis[x])return ;
    sum+=a[x];    //记录环内每个点的总和 
    siz++;        //环内有多少个点 
    MIN=min(MIN,a[x]);    //环内最小值 
    vis[x]=1;    //打上标记 
    dfs(pos[x]);    //下一个点 
}
int main()
{
    scanf("%d",&n);
    minn=MIN=inf;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        b[i]=a[i];
        minn=min(minn,a[i]);    //记录序列最小值 
    }
    sort(b+1,b+1+n);    //排序 
    for(int i=1;i<=n;i++)
        pos[i]=lower_bound(b+1,b+1+n,a[i])-b;    //记录排序后的位置 
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs(i);
            ans+=min(sum+MIN+minn*(siz+1),sum+MIN*(siz-2));
/*
        方法一:交换序列最小值和环内最小值 + 序列最小值 * 环内点数 
        方法二:环内最小值*环内点数。 
*/ 
            siz=0; sum=0; MIN=inf;
        }
    }
    printf("%lld",ans);
}

 

posted @ 2018-10-12 07:50  Manjusaka丶梦寒  阅读(244)  评论(0编辑  收藏  举报