uva1611-Crane

大意:给出一个1—n的排列,每次可以选择一个偶数区间,交换前一半和后一半。用不超过9^6次操作将其变为1—n的顺序。

提示:只需经过2n次操作

#include <cstdio>  

#include <algorithm>  
#include <cstring>  
using namespace std;  
const int maxn = 1e5 + 5;  
int a[maxn];  
int ans[maxn << 2];
//  交换偶数区间[L, R]前半部分和后半部分  
void swapp(int L,int R)  
{  
    for(int i=L;i<=(R+L-1)/2;i++)  
        swap(a[i],a[i+(R-L+1)/2]);  
}  
  
int main()  
{  
    int T;  
    scanf("%d", &T);  
    while(T--)  
    {  
        memset(ans,0,sizeof(ans));  
        int n;  
        scanf("%d", &n);  
        for(int i=1;i<=n;i++)  
            scanf("%d", a + i);  
        int t = n, cnt = 0;  
        // 让未归位的数归位
        while (t > 0)  
        {  
            int i;  
            //找到值为 t 对应的 下标 i
            for (i = 1; i <= t; i++)  
            {  
                if(a[i] == t)  
                break;  
            } 
            //将下标为i的数移到下标位t的位置 
            // 先移动到 t / 2 + 1 位置
            if(i != t && 2 * i < t)  
            {  
                int a,b;  
                if (t/2+1-i<=i)  
                {  
                    a=2*i-t/2;  
                    b=t/2+1;  
                }  
                else  
                {  
                    a=i;  
                    b=2*(t/2+1)-i-1;  
                }  
                ans[2*cnt]=a;  
                ans[2*cnt+1]=b;  
                cnt++;  
                swapp(a,b);  
                i = t/2+1;  
            }
            // 如果2*i>=t那么这一步操作可以省略上面中间移动步骤
            if(i!=t&&2*i>=t)  
            {  
                swapp(2*i-t+1,t);  
                ans[2*cnt]=2*i-t+1;  
                ans[2*cnt+1]=t;  
                cnt++;  
            }  
            t--;  
        }  
        printf("%d\n", cnt);  
        for(int j=0;j<cnt;j++)  
            printf("%d %d\n", ans[2*j],ans[2*j+1]);  
    }  
    return 0;  
}  

猜你喜欢

转载自blog.csdn.net/qq_36501295/article/details/77161324