Codeforces Round #252 (Div. 2) D

http://codeforces.com/problemset/problem/441/D

置换群的基本问题,一个轮换内交换成正常顺序需要k-1次,k为轮换内元素个数

两个轮换之间交换元素,可以把两个轮换合并成1个,总交换次数+1

一个轮换内部交换,可以把一个轮换拆分成两个,总交换次数-1

#include <iostream>

#include <cstdio>

#include <cstring>

#include <vector>

using namespace std ;

int n,m ;

int nxt[3005],vis[3005] ;

vector <pair<int,int> > ans ;

int cal()

{

    memset(vis,0,sizeof(vis)) ;

    int st=1 ;

    int cnt=0 ;

    for(int i=1 ;i<=n ;i++)

        if(!vis[i])

        {

            vis[i]=st++ ;

            int res=1 ;

            for(int j=nxt[i] ;!vis[j] ;j=nxt[j])

            {

                vis[j]=vis[i] ;

                res++ ;

            }

            cnt+=(res-1) ;

        }

    return cnt ;

}

int main()

{

    scanf("%d",&n) ;

    for(int i=1 ;i<=n ;i++)

        scanf("%d",&nxt[i]) ;

    scanf("%d",&m) ;

    while(1)

    {

        int ret=cal() ;

        if(ret==m)break ;

        if(ret<m)//两个轮换换,可以把两个轮换合并成1个,ret+1 ,保证字典序最小,所以和位置1换 

        {

            for(int i=2 ;i<=n ;i++)

                if(vis[i]!=vis[1])

                {

                    swap(nxt[1],nxt[i]) ;

                    ans.push_back(make_pair(1,i)) ;

                    break ;

                }

        }

        else//一个轮换内换,可以把一个轮换拆成两个,ret-1 

        {

            int i,j ;

            for(i=1 ;i<=n ;i++)

                if(nxt[i]!=i)break ;

            for(int j=i+1 ;j<=n ;j++)

                if(vis[j]==vis[i])

                {

                    swap(nxt[i],nxt[j]) ;

                    ans.push_back(make_pair(i,j)) ;

                    break ;

                }

        }

    }

    printf("%d\n",ans.size()) ;

    for(int i=0 ;i<ans.size() ;i++)

        printf("%d %d ",ans[i].first,ans[i].second) ;

    return 0 ;

}
View Code

 

你可能感兴趣的:(codeforces)