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;
    }
    

      

  • 相关阅读:
    inode满处理
    power shell 脚本了解
    免密脚本带端口
    linux文件 特殊权限的使用
    linux批量配置ip
    编译安装常用包+阿里镜像源-常用资源-系统-下载-科莱软件下载-docker仓库包-安全圈-杏雨梨云-图形界面安装-docker私有双仓库-阿里源报错处理-centos7目录大小
    expect免互交 常用编辑文本
    vim 插件 -- taglist
    vim 插件 -- ctags
    vim 插件 -- omnicppcomplete
  • 原文地址:https://www.cnblogs.com/Chierush/p/3210631.html
Copyright © 2011-2022 走看看