问题 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";
}