题解 P2226 【[HNOI2001]遥控赛车比赛】
(哇一道大水题没有人发题解)
这道题。。。
怎么说呢
实际上很简单,就和直接看上去一样,相信大家都会认为这是一道爆搜题。。
所以我索性就打了一个DFS。。
(代码略丑,不喜勿喷)
#include <bits/stdc++.h>
using namespace std;
const int fx[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
const int N = 100;
int n;
int m;
int Fx;
int Fy;
int Tx;
int Ty;
int res;
int s[N + 1][N + 1];
int rem[2][N + 1][N + 1];
bool remem(int x, int y, int tot, int k) {
if(tot > rem[0][x][y]) return 1;
else if(tot < rem[0][x][y]) return 0;
else return k <= rem[1][x][y];
}
void dfs(int x, int y, int k, int maxn, int tot, int la) {
if(!s[x][y] || x < 1 || y < 1 || x > n || y > m || remem(x, y, tot, k)) return;
rem[0][x][y] = tot;
rem[1][x][y] = k;
if(x == Tx && y == Ty) {
if(res < 0) res = tot;
else res = min(res, tot);
return;
}
for(int i = 0; i < 4; i++)
if(i != la) {
if(k == maxn)
dfs(x + fx[i][0], y + fx[i][1], 1, maxn, tot + 1, i);
}
else dfs(x + fx[i][0], y + fx[i][1], min(k + 1, maxn), maxn, tot + 1, i);
}
int main() {
scanf("%d%d%d%d%d%d", &n, &m, &Fx, &Fy, &Tx, &Ty);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d", &s[i][j]);
for(int i = 1; i <= 10; i++) {
res = -1;
memset(rem[0], 127, sizeof(rem[0]));
memset(rem[1], 0, sizeof(rem[1]));
dfs(Fx, Fy, i, i, 0, -1);
if(res == -1) break;
printf("%d %d\n", i, res);
}
return 0;
}
就像这样。。
然后30分,WA与TLE并存。。。
不明所以的我认为是DFS的锅,然后改了一个BFS。。
再贴一波:
#include <bits/stdc++.h>
using namespace std;
const int fx[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
const int N = 100;
int n;
int m;
int Fx;
int Fy;
int Tx;
int Ty;
int res;
int s[N + 1][N + 1];
int f[N + 1][N + 1][4];
int dis[N + 1][N + 1][4];
struct Node {
int x;
int y;
int z;
};
void print() {/*
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
printf("%-3d ", dis[i][j]);
puts("");
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
printf("%-3d ", f[i][j]);
puts("");
}*/
}
void BFS(int k) {
queue<Node>q;
while(!q.empty()) q.pop();
q.push((Node){Fx, Fy, 0});
q.push((Node){Fx, Fy, 1});
q.push((Node){Fx, Fy, 2});
q.push((Node){Fx, Fy, 3});
f[Fx][Fy][0] = 0;
f[Fx][Fy][1] = 0;
f[Fx][Fy][2] = 0;
f[Fx][Fy][3] = 0;
while(!q.empty()) {
Node now = q.front();
q.pop();
for(int i = 0; i < 4; i++) {
int x = now.x + fx[i][0];
int y = now.y + fx[i][1];
if(x > n || y > m || x < 1 || y < 1) continue;
if(dis[x][y][i] || !s[x][y] || (x == Fx && y == Fy)) continue;
if(i == now.z)
f[x][y][i] = min(k, f[now.x][now.y][now.z] + 1);
else {
if(f[now.x][now.y][now.z] != k) continue;
f[x][y][i] = 1;
}
q.push((Node){x, y, i});
dis[x][y][i] = dis[now.x][now.y][now.z] + 1;
if(x == Tx && y == Ty) {
res = dis[x][y][i];
return ;
}
}
}
}
int main() {
scanf("%d%d%d%d%d%d", &n, &m, &Fx, &Fy, &Tx, &Ty);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d", &s[i][j]);
for(int i = 1; i <= 10; i++) {
res = -1;
memset(f, 0, sizeof(f));
memset(dis, 0, sizeof(dis));
BFS(i);
print();
if(res == -1) break;
printf("%d %d\n", i, res);
}
return 0;
}
结果还是40分。。。
真是可怕。。。
但是至少没有TLE了。。
然后我就一直找啊找,发现了一个灵异事件:
之前你可能有一个弯绕不过去,
但是有可能你从别的地方绕一下再来这个点的时候就可以过了
上样例:
input:
10 5
4 2 10 3
1 1 1 1 1
0 1 0 0 1
0 1 0 1 1
1 1 0 1 1
0 1 1 1 1
1 1 1 1 0
1 1 1 1 1
0 0 1 0 1
0 0 1 0 1
0 0 1 0 1
output:
7
11
你的代码是不是输出:
7
17
这就是我要说的了
实际上它是这么搞的:
来回走很骚对吧。。
但是并不需要担心复杂度
中间只需要加上一个判断就好
代码中会有提到:
#include <bits/stdc++.h>
using namespace std;
const int fx[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
const int N = 100;
int n;
int m;
int Fx;
int Fy;
int Tx;
int Ty;
int res;
int s[N + 1][N + 1];
int f[N + 1][N + 1][4];
int dis[N + 1][N + 1][4];
struct Node {
int x;
int y;
int z;
};
void print() {/*
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
printf("%-3d ", dis[i][j]);
puts("");
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
printf("%-3d ", f[i][j]);
puts("");
}*/
}
void BFS(int k) {
queue<Node>q;
while(!q.empty()) q.pop();
q.push((Node){Fx, Fy, 0});
q.push((Node){Fx, Fy, 1});
q.push((Node){Fx, Fy, 2});
q.push((Node){Fx, Fy, 3});
f[Fx][Fy][0] = 0;
f[Fx][Fy][1] = 0;
f[Fx][Fy][2] = 0;
f[Fx][Fy][3] = 0;//0、1、2、3表示从哪个方向来的,f记录连续走了多少步
while(!q.empty()) {
Node now = q.front();
q.pop();
for(int i = 0; i < 4; i++) {
int x = now.x + fx[i][0];
int y = now.y + fx[i][1];
if(x > n || y > m || x < 1 || y < 1) continue;
if(!s[x][y] || (x == Fx && y == Fy)) continue;
int a;
if(i == now.z)
a = min(k, f[now.x][now.y][now.z] + 1);
else {
if(f[now.x][now.y][now.z] != k) continue;
a = 1;
}
if(dis[x][y][i] && a <= f[x][y][i]) continue;
//之前提到的就是这里了
//这里是说如果之前到过并且连续走的步数比之前记录的少就放弃
f[x][y][i] = a;
q.push((Node){x, y, i});
dis[x][y][i] = dis[now.x][now.y][now.z] + 1;
if(x == Tx && y == Ty) {
res = dis[x][y][i];
return ;
}
}
}
}
int main() {
scanf("%d%d%d%d%d%d", &n, &m, &Fx, &Fy, &Tx, &Ty);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d", &s[i][j]);
for(int i = 1; i <= 10; i++) {
res = -1;
memset(f, 0, sizeof(f));
memset(dis, 0, sizeof(dis));
BFS(i);
print();
if(res == -1) break;
printf("%d %d\n", i, res);
}
return 0;
}
嗯,这样就可以AC了