zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    关机相关(shutdown,reboot)
    软件架构学习小结
    颜色空间RGB与HSV(HSL)的转换
    OData语法
    拷贝构造函数,深拷贝,大约delete和default相关业务,explicit,给定初始类,构造函数和析构函数,成员函数和内联函数,关于记忆储存,默认参数,静态功能和正常功能,const功能,朋友
    登录模块
    TextView 使用自定义的字体和亮点
    基于Hama并联平台Finding a Maximal Independent Set 设计与实现算法
    VS2012使用XListCtrl
    ThinkPHP 3.2 开放 cache注缓存,过滤非法字符
  • 原文地址:https://www.cnblogs.com/Chierush/p/3210631.html
Copyright © 2011-2022 走看看