poj 3270

组合数学, 置换群

分析:原交换问题相当于一个置换群,因此可以分解成s个不相交循环的并,又因为每

个循环内的交换次数一定,我们选择循环中最小的一个数与其它数交换,代价最小。进而考虑到利用所有数中最小的一个m参与其他循环中的交换可能更优,加上这一点判断,问题得以解决。

 Cost = sum + Σ(i-> 1~s) min{(ki - 2)*ti, ti+ (k1+1)m};


#include

#include
#include
#include
#include
#include


using namespace std;
#define maxn 10005
#define maxg 100005


int ele[maxn];
int num[maxn], n, minn;
int pos[maxg];
bool vis[maxn];

void input()
{
    scanf("%d",&n);
    minn = 0x1f1f1f;
    for( int i = 0; i < n; i++)
    {
        scanf("%d",&ele[i]);
        num[i] = ele[i];
        if(minn > num[i])
          minn = num[i];
    }
}

int work( )
{

    int sum = 0;

//pos[ele[i]]] 为 排序之后元素ele[i]所对应位置, 便于寻找置换群, 元素多的时候可以考虑HASH

    for( int i = 0 ;i < n; i++)
      pos[ele[i]] = i;
//寻找置换群
    for( int i = 0; i < n; i++)
    {
        if(!vis[i])
        {
            int tem = i, len = 0, minc = num[i], res = 0;
            while(!vis[tem])
            {
                res += num[tem];
                len++;
                vis[tem] = 1;
                minc = min(minc, num[tem]);
                tem = pos[num[tem]];
            }
            sum = sum + res + min((len-2)*minc, minc + (len + 1) * minn);
        }
    }
    return sum;
}
int main()
{
    memset(vis, 0, sizeof(vis));
    input();
    sort(ele, ele + n);
    printf("%d\n",work());
    return 0;
}



你可能感兴趣的:(组合数学,POJ)