SPOJ1421_Goods_循环节

题意:1~n的一个排列,两两互换,每个位置每天只能做一次交换,问最多几天能交换成1~n,并且输出交换步骤。

解法:把该置换中所有的循环节找出,各循环节之间的交换是并行的,两两不相关,每天只需在循环节内部交换。

  若循环节长度为1,则无需交换,若循环节长度为2,则只需交换一次,若循环长度>2,则只需要交换2次。

  置换方法:每个循环节中的第一个和最后一个交换,第二个和倒数第二个交换...

  至于为什么只需两次,可以在纸上模拟一下置换过程,按上述置换方法一次交换后,一个循环节变成了(n-1)/2个长度为2的循环节,可以一次并行交换。

代码如下:

/*************************************************************************
    > File Name: D.cpp
    > Author: Chierush
    > Mail: qinxiaojie1@gmail.com 
    > Created Time: 2013年07月24日 星期三 09时04分46秒
 ************************************************************************/

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <set>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <cmath>
#include <algorithm>

#define LL long long
#define LLU unsigned long long

using namespace std;

bool vis[5005];
int c[5005],n,a[5005],b[5005],_count;
vector<int>s[5005];

inline void swap(int &x,int &y)
{
    x=x^y,y=x^y,x=x^y;
}

void dfs(int x)
{
    int y=a[x],Count=1;
    while (y!=x)
    {
        ++Count;
        y=a[y];
    }
    c[x]=Count;
    y=a[x];
    while (y!=x)
    {
        vis[y]=true;
        c[y]=Count;
        y=a[y];
    }
    s[_count].clear();
    if (Count>1)
    {
        s[_count].push_back(x);
        y=a[x];
        while (y!=x)
        {
            s[_count].push_back(y);
            y=a[y];
        }
        ++_count;
    }
}

int main()
{
    scanf("%d",&n);
    _count=0;
    for (int i=1;i<=n;++i)
        scanf("%d",&b[i]);
    for (int i=1;i<=n;++i)
        a[b[i]]=i;
    for (int i=1;i<=n;++i)
        if (!vis[i])
        {
            vis[i]=true;
            dfs(i);
        }
    int ans=0;
    for (int i=1;i<=n;++i)
        if (c[i]>ans)
            ans=c[i];
    if (ans==1) ans=0;
    else if (ans==2) ans=1;
    else ans=2;
    printf("%d
",ans);
    while (ans)
    {
        int z=0;
        for (int i=0;i<_count;++i)
            z+=s[i].size()/2;
        printf("%d",z);
        for (int i=0;i<_count;++i)
        {
            for (int j=0;j<s[i].size()/2;++j)
            {
                printf(" %d-%d",s[i][j],s[i][s[i].size()-j-1]);
                swap(a[s[i][j]],a[s[i][s[i].size()-j-1]]);
            }
        }
        printf("
");
        _count=0;
        memset(vis,0,sizeof(vis[0])*(n+1));
        memset(c,0,sizeof(c[0])*(n+1));
        for (int i=1;i<=n;++i)
            if (!vis[i])
            {
                vis[i]=true;
                dfs(i);
            }
        ans=0;
        for (int i=1;i<=n;++i)
            if (c[i]>ans)
                ans=c[i];
        if (ans==1) ans=0;
        else if (ans==2) ans=1;
        else ans=2;
        /*for (int i=1;i<=n;++i)
            printf("%d ",a[i]);
        printf("
");*/
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Chierush/p/3210631.html