题意
n
2
n^2
n2的网格图,对于
(
i
,
j
)
(i,j)
(i,j),编号为
(
i
−
1
)
∗
n
+
j
(i-1)*n+j
(i−1)∗n+j。
初始图上每个格子为
1
1
1,按给定顺序求出每个点到达边界的最短路,路径长度为经过的
1
1
1的数量,不包括自己。
计算完当前的之后,令当前格子为
0
0
0
使得最短路总和最小。
题解
这题比较巧妙,容易证明初始图的最短路,每个点加起来之后是这样的一张图。
最外层是
1
1
1,第二层围成一个圈是
2
2
2,一直到
n
2
\frac{n}{2}
2n。
我们可以分成四部分计算总和,考虑左上角,最后一行是
1
2
3
4...
n
2
1\ 2\ 3\ 4...\frac{n}{2}
1 2 3 4...2n,是
n
2
n^2
n2的。
显然行数往上,总和越少,不过我们估算成
n
2
n^2
n2。
最后这个格子总和是
n
3
n^3
n3的,乘以
4
4
4,依然是
n
3
n^3
n3的。
我们每次令一个格子为
0
0
0,可以以其为重心往外松弛,每次遇到最短路变小在更新。
每次入队,必然有
−
1
-1
−1,所以至多
n
3
n^3
n3次入队。
所以复杂度可以保证。
好巧妙的证明方法, A G C AGC AGC厉害了。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn = 3e5+10;
const int maxm = 1e6+10;
const int mod = 998244353;
int n;
int val[505][505],dist[505][505];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
void bfs(int sx,int sy){
queue<pair<int,int> >q;
q.push(make_pair(sx,sy));
while(!q.empty()){
int x=q.front().first,y=q.front().second;q.pop();
for(int i=0;i<4;i++){
int newx=x+dx[i],newy=y+dy[i];
if(newx<0||newx>n||newy<0||newy>n)continue;
if(dist[newx][newy]>dist[x][y]+val[x][y]){
dist[newx][newy]=dist[x][y]+val[x][y];
q.push(make_pair(newx,newy));
}
}
}
}
int main(){
cin>>n;
FOR(i,1,n)FOR(j,1,n)dist[i][j]=min(min(i-1,j-1),min(n-j,n-i)),val[i][j]=1;
int ans=0;
FOR(i,1,n)FOR(j,1,n){
int P;cin>>P;
int x=(P+n-1)/n;
int y=P%n==0?n:P%n;
val[x][y]--;
bfs(x,y);
ans+=dist[x][y];
}
cout<<ans<<endl;
}