POJ3270 置换群

来源:互联网 发布:蜂窝数据没有app选项 编辑:程序博客网 时间:2024/06/05 06:47

给你一些没有重复的数,你只能交换其中两个数字,但是你要付出的代价是这两个数字之和。问你如何交换使得这些数字递增且代价最小。
置换群的概念:这些数字将会形成几个循环体。
对于每个循环体
1、循环体内和 + 循环体内最小值 + 所有数内最小值 * (该循环体内数字个数 + 1)
2、循环体内和 + 循环体内最小值 * (该循环体内数字个数 - 1)
以上两种取最小值即可。

//#pragma comment(linker, "/STACK:61400000,61400000")
#include <set>
#include <map>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <cstdio>
#include <vector>
#include <string>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

#define pi 3.1415926535897932385
#define LL64 __int64
#define LL long long
#define oo 2147483647
#define N 100050
#define M 100

int a[N];
int b[N];
int h[N];
bool p[N];

int main()
{
    int n;
    
    //freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    //int _case = 1;
    //scanf("%d", &t);
    //while (t--)
    //for (int _case = 1; _case <= t; _case++)
    while (~scanf("%d", &n))
    {
        memset(p, 0, sizeof(p));
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            b[i] = a[i];
            h[a[i]] = i;
        }
        sort(b, b + n);
        int a1 = b[0];
        int sum = 0;
        while (n)
        {
            int i = 0;
            while (p[i]) i++;
            p[i] = 1;
            int num = 1;
            int x = i;
            int s1 = 0;
            int s2 = 0;
            while (1)
            {
                x = h[b[x]];
                if (x == i) break;
                num++;
                p[x] = 1;
                s1 += b[x];
            }
            n -= num;
            s2 = s1;
            s1 += b[i] * (num - 1);
            s2 += b[i] * 2 + (num + 1) * a1;
            sum += (s1 < s2 ? s1 : s2);
        }
        printf("%d\n", sum);
    }
}
0 0
原创粉丝点击