【问题描述】
windy有一块矩形土地,被分为 N*M 块 1*1 的小格子。
有的格子含有障碍物。
如果从格子A可以走到格子B,那么两个格子的距离就为两个格子中心的欧几里德距离。
如果从格子A不可以走到格子B,就没有距离。
如果格子X和格子Y有公共边,并且X和Y均不含有障碍物,就可以从X走到Y。
如果windy可以移走T块障碍物,求所有格子间的最大距离。
保证移走T块障碍物以后,至少有一个格子不含有障碍物。
【输入格式】
输入文件maxlength.in第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0'表示空格子,'1'表示该格子含有障碍物。
【输出格式】
输出文件maxlength.out包含一个浮点数,保留6位小数。
【输入样例一】
3 3 0
001
001
110
【输出样例一】
1.414214
【输入样例二】
4 3 0
001
001
011
000
【输出样例二】
3.605551
【输入样例三】
3 3 1
001
001
001
【输出样例三】
2.828427
【数据规模和约定】
20%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 0 。
40%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 2 。
100%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 30 。
此题考察最短路径。建图时,将每个点向它的上下左右各连一条边,边的权值为改变两顶点上障碍的数目之和。
然后对每个点进行一次SPFA,将所有与其距离不超过2T的点到该点的最大距离找出来,再取所有的最大距离即为所求。
提交情况:提交五次。
第一次:0分。(TimeLimitExceed * 10,须用链表解决。)
第二次:20分。(WrongAnswer * 8,建图有误。)
第三次:10分。(WrongAnswer * 9,建图有误。)
第四次:70分。(WrongAnswer * 3)
第五次:100分。
Accode:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
const char fi[] = "maxlength.in";
const char fo[] = "maxlength.out";
const int maxR = 40;
const int maxN = 1010;
const int SIZE = 1000000;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};
struct Edge
{
int u, v, d;
Edge *next;
};
int dist[maxR][maxR];
Edge *edge[maxR][maxR];
int q[SIZE][2];
bool obs[maxR][maxR];
bool marked[maxR][maxR];
int x[maxN];
int y[maxN];
int n, m, T, tot, f, r;
double ans, init;
void init_file()
{
freopen(fi, "r", stdin);
freopen(fo, "w", stdout);
return;
}
double sqr(double x) {return x * x; }
double d(double x1, double y1,
double x2, double y2)
{
return sqrt(sqr(x1 - x2) + sqr(y1 - y2));
}
void insert(int x, int y, int u, int v, int d)
{
Edge *p = new Edge;
p -> u = u;
p -> v = v;
p -> d = d;
p -> next = edge[x][y];
edge[x][y] = p;
}
void readdata()
{
scanf("%d%d%d", &n, &m, &T);
for (int i = 1; i < n + 1; ++i)
{
getchar();
for (int j = 1; j < m + 1; ++j)
{
obs[i][j] = getchar() - '0';
if (obs[i][j])
{
x[++tot] = i;
y[tot] = j;
}
}
}
for (int i = 1; i < n + 1; ++i)
for (int j = 1; j < m + 1; ++j)
for (int k = 0; k < 4; ++k)
{
int i1 = i + dx[k],
j1 = j + dy[k];
if (i1 < 1 || i1 > n || j1 < 1 || j1 > m)
continue;
insert(i, j, i1, j1,
obs[i][j] + obs[i1][j1]);
}
return;
}
void Enq(int X, int Y)
{
q[r][0] = X;
q[r][1] = Y;
if (++r > SIZE) r -= SIZE;
return;
}
int Front_x()
{
return q[f][0];
}
int Front_y()
{
return q[f][1];
}
void Deq()
{
if (++f > SIZE) f -= SIZE;
return;
}
void Spfa(int X, int Y)
{
f = r = 0;
memset(dist, 0x3f, sizeof(dist));
memset(marked, 0, sizeof(marked));
Enq(X, Y);
marked[X][Y] = 1;
dist[X][Y] = 0; //细节处应注意。
while (f != r)
{
int _x = Front_x();
int _y = Front_y();
Deq(); //细节处应注意。
marked[_x][_y] = 0;
for (Edge *p = edge[_x][_y]; p; p = p -> next)
{
int _u = p -> u, _v = p -> v;
if (dist[_x][_y] + p -> d < dist[_u][_v])
{
dist[_u][_v] = dist[_x][_y] + p -> d;
if (!marked[_u][_v])
{
Enq(_u, _v);
marked[_u][_v] = 1;
}
}
}
}
return;
}
void work()
{
init = sqrt(sqr(n - 1) + sqr(m - 1));
for (int i = 1; i < n + 1; ++i)
for (int j = 1; j < m + 1; ++j)
if (!obs[i][j])
//要从一个非障碍点出发,且两端不能同时为非障碍点。
{
Spfa(i, j);
for (int i1 = 1; i1 < n + 1; ++i1)
for (int j1 = 1; j1 < m + 1; ++j1)
if (i1 != i || j1 != j)
{
double tmp = d(i, j, i1, j1);
if (dist[i1][j1] <= (T << 1) && tmp > ans)
ans = tmp;
}
}
printf("%.6lf\n", ans);
return;
}
int main()
{
init_file();
readdata();
work();
return 0;
}