ZOJ3838 - Infusion Altar(找规律模拟)

来源:互联网 发布:linux 多进程 例子 编辑:程序博客网 时间:2024/05/17 22:08

【题目】

Infusion Altar

 


 

Time Limit: 2 Seconds                                    Memory Limit:65536 KB                            

 


 

Bob is recently playing a game called Minecraft,  especially a mod calledThaumcraft. It is a mod of magic.

Usually, Bob has Obsessions with Symmetry while playing Minecraft. This obsession is useless in the gameplay generally. However,  inThaumcraft, the infusion altar requires symmetry to keep it stable.

Bob built an infusion altar in his secret chamber, but it  was not so symmetrical. After some explosions, Bob decided  to fix the infusion altar to make it symmetrical.

InfusionAltar

You will be given the map of Bob's secret chamber. It is of size n*n(n is an odd number), the infusion altar is  always at the center of his secret chamber. The following picture  is a typical map. The 3*3 square in the center is the Infusion Altar,  it is a multi-block structure. Here, '#' means Runic Matrix, 'o'  means Arcane Pedestal, '.' means an empty place, 'a'-'z' means  occult paraphernalia(like skulls, crystals and candles) Bob placed  around the Infusion Altar. There will not be characters other than  'a'-'z', '.', '#'.

.aab.bo.obb.#.abo.obbbab.

Now, the question is that at least how many blocks need to be changed  to make the whole map symmetrical. Here, being symmetrical means having all four axes of symmetry for a square. Also, you can change any character  on the map to any other character.

Input

There are multiple cases. The first line contains one integer T which is the number of test cases.
For each case, The first line contains an integer n ( 3 ≤ n ≤ 99, and n is an odd number)
For the next n lines, each line contains n characters showing the map.
It is guaranteed that the Infusion Altar is at the center of the map.
It is guaranteed that only 'a'-'z' and '.' will appear out of the Infusion Altar.

Output

One integer for each test case which is the least number of blocks that should be changed.

Sample Input

33o.o.#.o.o5.aab.bo.obb.#.abo.obbbab.5aabbaao.oaa.#.aao.oaaaaaa

Sample Output

032

Hint

The first sample is a standard Infusion Altar.
In second sample, Bob will change his secret chamber to the following map.

.bab.bo.oba.#.abo.ob.bab.

 


                            Author: ZHU, Jiale; GONG, Yuan
                                         Source: ZOJ Monthly, November 2014
【分析】题目是求最少改变多少个格子使得棋盘满足4条对称轴都对称,比赛的时候就死在all four axes,不知道怎么了一直把axes看成是区域,唉不说了,心痛。

知道是需要4条对称轴对称就好办了

先画个7*7的图

4条对称轴如上,对于红色字1的格子,其实只有这红色这1~8有关系,与其他点没关联,这样我们只需枚举一个点,

然后考虑每个点所关联的8个点,在这8个点中求出让他们变成相同字符的最小变化次数,然后用vis标记出这遍历过的8个点,再枚举矩阵遍历没访问过的其他点。

问题在于如何通过一个点求出其他7个点的坐标,仔细观察可以先得出1~4点的关联:

假设1点坐标为(i,j),则2为(i,n-j-1),3:(n-i-1,j),4:(n-i-1,n-j-1);

通过这四个点可以推出其他4个点坐标分别为:

5(j,i)  6(n-j-1,i)  7(j,n-i-1)  8(n-j-1,n-i-1)

现在知道了坐标的计算,那么离解决不远了;

还有一个问题就是如何求出这8个点最小需要变化几次让他们都相同。

仔细观察,其实不难,我们记录下每个字符出现的次数,然后求出单个字符最多出现的次数mx,则8-mx就是答案,

但是对于在4条对称轴上的点需要特判,其实只要都除以就行,变成4-mx/2,因为他们只有4个点关联,除2蛆去重即可。

这样就解决了,个人认为代码还是蛮简洁的。

【AC CODE】0ms

#include <cstdio>#include <cstring>#include <cctype>#include <cmath>#include <map>//#include <unordered_map>#include <queue>#include <stack>#include <vector>#include <string>#include <algorithm>using namespace std;#define rep(i,a,n) for(int i = a; i < n; i++)#define repe(i,a,n) for(int i = a; i <= n; i++)#define per(i,n,a) for(int i = n; i >= a; i--)#define clc(a,b) memset(a,b,sizeof(a))#define INF 0x3f3f3f3ftypedef long long LL;int n;int get_sum(bool mid,char *a)//获得8个点最小变化次数{int vis[300]={0}, mx = 0;rep(i,0,8) vis[a[i]]++;int ans;repe(i,'a','z') mx = max(mx,vis[i]);mx = max(vis['.'],mx);mx = max(vis['#'],mx);if(mid) ans = 4-mx/2;else ans = 8-mx;return ans;}char a[110][110];int main(){#ifdef SHYfreopen("e:\\1.txt", "r", stdin);#endifint t;scanf("%d%*c", &t);while(t--){scanf("%d%*c", &n);rep(i,0,n)scanf("%s", a[i]);int ans = 0;int vis[110][110]={0};rep(i,0,n){rep(j,0,n){if(!vis[i][j]){char buf[9]={a[i][j],a[n-i-1][j],a[i][n-j-1],a[n-i-1][n-j-1],a[j][i],a[n-j-1][i],a[j][n-i-1],a[n-j-1][n-i-1]};buf[8] = 0;ans += get_sum((i == n/2 || j == n/2 || i == j || n-1 == i+j),buf);vis[i][j] = vis[n-i-1][j] = vis[i][n-j-1] = vis[n-i-1][n-j-1] = 1;vis[j][i] = vis[n-j-1][i] = vis[j][n-i-1] = vis[n-j-1][n-i-1] = 1;}}}printf("%d\n", ans);}return 0;}


 

 

0 0