Ring
时间限制: 1 Sec 内存限制: 128 MB
题目描述
一个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。
先将一个个环全部拆下来放到数组中,然后将初始状态的和现在的状态比较,是否可以到达。
/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
typedef long long LL;
using namespace std;
int n;
int a[7][7], b[7][7];
int p[5][40], now[5][40], ans; //now记录的现在的各个环,p记录的初始的各个环
bool dfs(int x){
if(x == (n + 1) / 2 + 1) return true;
int cnt = 1, f = 0, t = 1, num = 0;
while(now[x][t] != p[x][1] && t <= now[x][0]) t++, num++;
while(cnt <= p[x][0]){
if(now[x][t] != p[x][cnt]){
f = 1;
break;
}else{
if(t == now[x][0]) t = t - now[x][0] + 1;//注意是个环
else t++;
cnt++;
}
}
ans += min(num, now[x][0] - num);//因为可以是逆时针,所以要取最小值
if(!f) return dfs(x + 1);
else return false;
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
scanf("%d", &a[i][j]);
}
}
int cnt = 1;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
b[i][j] = cnt++;
}
}
int t = (n - 1) * 4;//每一个环的数字的个数
for (int i = 1; i <= (n + 1) / 2; i++){
int x = i, y = i;
cnt = 1;
if((n & 1) && !t) t = 1;//奇数的时候,当中有一块
now[i][0] = t;
int f = 1, tt = t / 4;
while(cnt <= t){
now[i][cnt++] = a[x][y];
if(f == 1){
y++;
if(y == i + tt) f = 2;
}else if(f == 2){
x++;
if(x == i + tt) f = 3;
}else if(f == 3){
y--;
if(y == i) f = 4;
}else x--;
}
t -= 8;
}
t = (n - 1) * 4;
for (int i = 1; i <= (n + 1) / 2; i++){
int x = i, y = i;
cnt = 1;
if((n & 1) && !t) t = 1;
p[i][0] = t;
int f = 1, tt = t / 4;
while(cnt <= t){
p[i][cnt++] = b[x][y];
if(f == 1){
y++;
if(y == i + tt) f = 2;
}else if(f == 2){
x++;
if(x == i + tt) f = 3;
}else if(f == 3){
y--;
if(y == i) f = 4;
}else x--;
}
t -= 8;
}
if(dfs(1)) printf("YES\n%d\n", ans);
else printf("NO\n");
return 0;
}
/**/