SPOJ1421_Goods_循环节

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

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

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

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

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

代码如下:

/*************************************************************************

    > File Name: D.cpp

    > Author: Chierush

    > Mail: [email protected] 

    > 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\n",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("\n");

        _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("\n");*/

    }

    return 0;

}

  

你可能感兴趣的:(poj)