问题 : 棋子
题目描述
FJ的棋盘地被划分成R行C列,共R×C个格子。一开始时,如果某个格子有棋子,那么用‘x’表示,如果没有棋子则用‘.’表示。现在FJ有Q个操作,每个操作的格式是给出两个整数:a 和 b,表示询问到目前为止,距离第a行第b列格子最近的棋子在哪里?输出该棋子所在格子与第a行第b列格子的距离。当你输出该距离之后,FJ在第a行第b列的格子增加一个棋子。 现在给出两个格子的距离计算公式:记第a行第b列的格子是(a,b),第c行第d列的格子是(c,d),那么格子(a,b)与格子(c,d)的距离=(a-c) × (a-c) + (b-d)×(b-d)
。
输入
第一行,R和C。 1 <= R, C <= 500
。
接下来是R行C列棋盘,每个元素要么是x’,要么是‘.’,数据保证至少有一个棋子。
接下来一行,是一个整数Q,表示总共有Q个操作。1<=Q<=100000
。
接下来有Q行,每行表示一个操作,格式是两个整数:a和b。意义如题目所示。
输出
共Q行,每行输出一个距离。
样例
#1
输入
3 3
x..
...
...
3
1 3
1 1
3 2
输出
4
0
5
提示
样例解释
棋盘是3行3列,一开始只有第1行第1列的格子有棋子。
FJ总共有3个操作,第一个操作:询问离第1行第3列最近的棋子所在格子与第1行第3列格子的距离是多少?由于到目前为止只有第1行第1列有棋子,那么答案肯定就是:(1-1)*(1-1) + (1-3)*(1-3)=4
。所以你要输出4。然后FJ在第1行第3列的格子增加一个棋子。
第二个操作:询问离第1行第1列最近的棋子所在格子与第1行第1列格子的距离是多少?虽然到目前为止已经有了两个棋子,但显然, 第1行第1列的棋子更近些,那么答案肯定就是:(1-1)*(1-1) + (1-1)*(1-1)=0
。所以你要输出0。然后FJ在第1行第1列的格子增加一个棋子。
第三个操作:询问离第3行第2列最近的棋子所在格子与第3行第2列格子的距离是多少?虽然到目前为止已经有了3个棋子,答案肯是: (1-3)*(1-3) + (1-2)*(1-2)=5
。所以你要输出5。然后FJ在第3行第2列的格子增加一个棋子。
对于30
%的数据,```Q <= 500``。
以前的思路
这题我想过很多思路,用一个数组装下棋子的位置这种方法会TLE
。如果用广搜附近的点也会TLE
,还如果直接爆搜更是TLE
。
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y;
};
const int N = 250010;
int n,m;
vector<node> v;
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin >> c;
if(c=='x')
v.push_back({i,j});
}
}
int q,a,b,ans;
cin >> q;
while(q--){
cin >> a >> b;
ans = 2147483647;
for(int i=0;i<v.size();i++){
ans = min(ans,(a-v[i].x)*(a-v[i].x)+(b-v[i].y)*(b-v[i].y));
}
v.push_back({a,b});
cout <<ans <<endl;
}
}
/**************************************************************
Language: C++
Result: 时间超限40
****************************************************************/
以上代码就是我用vector可变长数组做的最高分。
AC思路
后来看了看题解,发现这道题也是一个动态规划问题。
设f[i][j]
为第 i 行,第 j 列的最小距离。
然后状态转移:
f[i][j] = min(f[i][j],p(j-k))
这里的p()是平方的意思。
这可能有点难理解
先说效果:时间复杂度O((k+n)*q+k*n)
这种方法就是把这个地图拆分成多个横着的一维数组,让他更新的时候可以只更新这一行,要取得时候在遍历一下竖着的一条看看哪个横着的距离+这一行的行号到b(也就是竖着的距离)最小输出这个值就行了。之后我们更新也不需要全图更新,只需要更新这一行的所有数就可以了。
如果还是不明白,上代码!
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
using namespace std;
const int INF = 1234567890;
char mp[510][510];
int f[510][510],n,m,q;
//vector<int> v[2];
int p(int x){return (x)*(x);}
int main(){
cin >> n >> m;for(int i=1;i<=n;i++)
scanf("%s",mp[i]+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j] = INF;
for(int k=1;k<=m;k++){
if(mp[i][k]=='x'){
f[i][j] = min(f[i][j],p(j-k));
}
}
}
}
scanf("%d",&q);
int a,b;
while(q--){
scanf("%d%d",&a,&b);
int ans=INF;
for(int i=1;i<=n;i++){
ans = min(f[i][b]+p(a-i),ans);
}
printf("%d\n",ans);
mp[a][b] = 'x';
for(int j=1;j<=m;j++){
f[a][j] = min(f[a][j],p(j-b));
}
}
return 0;
}
/**************************************************************
Language: C++
Result: 正确100
Time:748 ms
Memory:2984 kb
****************************************************************/
这个就是AC的代码,这里我把cin和cout改成了scanf和printf,然后又加了一个火车头,否则还是有点问题哈哈。