九野的博客,转载请注明出处:http://blog.csdn.net/acmmmm/article/details/11391275
题意:该矩阵中,可以顺时针或逆时针旋转每一圈,问旋转至少几次可以使主对角线和副对角线和最大
下面代码先计算每一圈的和最大,最后加上中间的点
题目保证矩阵边长为奇数
做起来有点繁琐,下面k表示第k圈,最中间是第0圈,只要for那一圈的第一排数字即可。
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <queue>
#include <stdlib.h>
#include <cstdlib>
#include <set>
#include <math.h>
#include <vector>
#define inf 107374182
#define N 105
#define im -1000000
#define ll int
using namespace std;
inline ll Max(ll a,ll b){return a>b?a:b;}
inline ll Min(ll a,ll b){return a<b?a:b;}
int map[N][N],n;
int sum(int k,int h,int l){
k=(n/2)+1-k;
return map[k+h][k+l];
}
int sum1(int k,int h,int l){
int len=k*2;
k=(n/2)+1-k;
int x=h,y=l;
if(x>len){y+=(x-len);x=len;}
if(x<0){y-=0-x;x=0;}
if(y>len){x+=(y-len);y=len;}
if(y<0){x-=0-y;y=0;}
return map[k+x][k+y];
}
int GO(int x,int y,int k){
if(x==0)return Min(y,k-y);
return Min(x,k-x);
}
int abs(int k,int i){
if(i>k)return i-2*(i-k);
return i+2*(k-i);
}
int main(){
ll i,j,k,go;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&map[i][j]);
int step=0,ans=0;
int zhongdian=(n/2)+1;
for(k=1;k<=(n>>1);k++)
{
int len=k*2,maxx=-1,temp;
go=10000;
for(i=0;i<k*2+1;i++)
{
temp=sum(k,0,i)+sum(k,len,abs(k,i));
temp+= sum1(k,0,i+len)+sum1(k,len,abs(k,i)-len);
if(temp>maxx)
{
maxx=temp;
go=GO(0,i,len);
}
else if(temp==maxx)
if(go>GO(0,i,len))
go=GO(0,i,len);
}
step+=go;
ans+=maxx;
}
printf("%d %d\n",ans+map[zhongdian][zhongdian],step);
}
return 0;
}
/*
5
9 3 2 5 9
7 4 7 5 4
6 9 3 9 3
5 2 8 7 2
9 9 4 1 9
*/