传送门:bzoj1295
题解
考虑建图连边跑最短路。
每个点向周围四个方向的点连边,边权为(
0/1
0
/
1
,连向的点为障碍时为
1
1
,否则为),两点可以互相到达就转换成了:两点之间最短路距离
≤T
≤
T
(显然还需要特殊考虑起点是否为障碍)。
直接暴力以每个点为起点跑单元最短路,顺便每次和更新后距离第一次
≤T
≤
T
的点求个欧几里得距离(
floyd
f
l
o
y
d
也行)。
代码
#include<bits/stdc++.h>
#define rc(x,y) (((x)-1)*m+y)
#define db double
using namespace std;
const int N=990,inf=2e9;
struct P{
int x,y;
P(){}
P(int X,int Y){x=X;y=Y;}
};
int n,m,lim,T,dis[N],vis[N];
int head[N],to[N<<2],nxt[N<<2],w[N<<2],tot;
db mx;
inline void lk(int u,int v,int cc)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=cc;
}
char s[35][35];
inline db sqr(db x){return x*x;}
inline db dist(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
inline P rv(int x){return P((x-1)/m+1,(x-1)%m+1);}
queue<int>Q;
inline void solve(int st,P A)
{
int i,j,x,ty=T;ty-=(s[A.x][A.y]-'0');
for(i=1;i<=lim;++i) dis[i]=inf;
dis[st]=0;Q.push(st);vis[st]=1;
for(;!Q.empty();){
x=Q.front();Q.pop();
for(i=head[x];i;i=nxt[i]){
j=to[i];if(dis[j]>dis[x]+w[i]){
if(dis[j]>ty && dis[x]+w[i]<=ty) mx=max(mx,dist(A,rv(j)));
dis[j]=dis[x]+w[i];
if(!vis[j]) {Q.push(j);vis[j]=1;}
}
}
vis[x]=0;
}
}
int main(){
int i,j,len,res;
scanf("%d%d%d",&n,&m,&T);
for(i=1;i<=n;++i) scanf("%s",s[i]+1);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j){
res=rc(i,j);
if(i>1) lk(res,res-m,(s[i-1][j]-'0'));
if(i<n) lk(res,res+m,(s[i+1][j]-'0'));
if(j>1) lk(res,res-1,(s[i][j-1]-'0'));
if(j<m) lk(res,res+1,(s[i][j+1]-'0'));
}
lim=n*m;
for(i=1;i<=lim;++i)
solve(i,rv(i));
printf("%.6lf\n",mx);
}