Ring 余姚小学题 wlacm

                                                      问题 K: Ring

                                                                    时间限制: 1 Sec  内存限制: 256 MB
                                                                                    提交: 18  解决: 4
                                                              [提交][状态][讨论版][命题人: 2015014139]

题目描述

一个n×n的矩阵,可以分成一些环(如图a中,n=5,可以划分成3个环),每个环上的数字都可以沿着环顺时针或者逆时针转动,每次转动只能将任意一个环顺时针或者逆时针转动一格。初始状态如图a,将矩阵从左到右、从上到下依次用1到n×n填满。现在给你一个局面,请问至少通过多少次环的转动能使矩阵恢复到初始状态?

例如,图b的局面可以通过,最外圈逆时针转动两格,第二圈顺时针转动一格,恢复到初始状态(图a),即至少转动三次。

 

输入

第一行输入一个正整数n。接下来n行,每行输入n个用空格隔开的正整数,第i行第j个数aij(aij≤1,000),表示给定的n×n的矩阵局面。

输出

若给定的矩阵局面可以通过环的转动回到初始状态,则输出两行,第一行为“YES”(输出不包含引号),第二行为一个非负整数,表示至少需要转动几次;否则,输出“NO”(输出不包含引号)。

样例输入

5
11 6 1 2 3
16 8 9 14 4
21 7 13 19 5
22 12 17 18 10
23 24 25 20 15

样例输出

YES
3

提示

 


对于 40% 的数据,满足n≤4,且给定局面中1到n×n的数字都出现且仅出现一次。

对于 80% 的数据,满足n≤6,且给定局面中1到n×n的数字都出现且仅出现一次。

对于 100% 的数据,满足n≤6。

 

 

这是一题余姚小学题,也算是acm入门水题了。。。还是没能一次A。。。唉,主要还是细节。

做法是 考虑先做一个正确状态的的图,然后把每一圈的数字放在数组里,每放进去一圈,再在后面放一圈一样的,这样就额能解决首位拼接的问题。步数就是Min(现在位置到正确位置的曼哈顿距离,一圈个数-曼哈顿距离)

水题,直接放代码了。

#include<iostream>
#include<cstring>
using namespace std;
int n;
int a[10][10];
int b[50],c[10][10];
void init(int nn){
    int k=1;
    for(int i=0;i<nn;i++)
        for(int j=0;j<nn;j++)
            c[i][j]=k++;
}
void want(int nn){
    int i=nn-1,j=nn-1;
    int k=0;
    for(;j<n-nn;j++)
        b[k++]=c[i][j];
    for(;i<n-nn;i++)
        b[k++]=c[i][j];
    for(;j>nn-1;j--)
        b[k++]=c[i][j];
    for(;i>nn-1;i--)
        b[k++]=c[i][j];
    for(int o=0;o<k;o++)
        b[k+o]=b[o];
}
int is(int nn,int k){
    int i=nn-1,j=nn-1;
    for(;j<n-nn;j++)
        if(a[i][j]!=b[k++])
            return -1;
    for(;i<n-nn;i++)
        if(a[i][j]!=b[k++])
            return -1;
    for(;j>nn-1;j--)
        if(a[i][j]!=b[k++])
            return -1;
    for(;i>nn-1;i--)
        if(a[i][j]!=b[k++])
            return -1;
    return 1;
}
int sum=0;
int main(){
    scanf("%d",&n);
    init(n);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            scanf("%d",&a[i][j]);
    for(int i=1;i<=n/2;i++){
        want(i);
        int k=0;
        for(k=0;k<4*(n-1);k++)
            if(b[k]==a[i-1][i-1])
                break;
        if(k==4*(n-1)){
            cout<<"NO"<<'\n';
            return 0;
        }
        if(is(i,k)==-1){
            cout<<"NO"<<'\n';
            return 0;
        }
        else
           sum+=min(4*(n-1)-k,k);

    }
    if((n%2&&c[n/2][n/2]==a[n/2][n/2])||(n%2==0))
      cout<<"YES\n"<<sum<<'\n';
    else
        cout<<"NO\n";


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值