[SCOI2009]最长距离

Description

点击查看题面

windy有一块矩形土地,被分为 NM 块 11 的小格子。 有的格子含有障碍物。 如果从格子A可以走到格子B,那么两个格子的距离就为两个格子中心的欧几里德距离。 如果从格子A不可以走到格子B,就没有距离。 如果格子X和格子Y有公共边,并且X和Y均不含有障碍物,就可以从X走到Y。 如果windy可以移走T块障碍物,求所有格子间的最大距离。 保证移走T块障碍物以后,至少有一个格子不含有障碍物。

输入格式
第一行包含三个整数,N M T。 接下来有N行,每行一个长度为M的字符串,'0'表示空格子,'1'表示该格子含有障碍物。

输出格式
包含一个浮点数,保留6位小数。

输入输出样例
输入 #1
3 3 0
001
001
110
输出 #1
1.414214

输入 #2
4 3 0
001
001
011
000
输出 #2
3.605551

输入 #3
3 3 1
001
001
001
输出 #3
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 。

Problem solving

这道题的意思就是有一个的图,某些点存在障碍,问你在移走最多个障碍物之后,可以达到的最大的两点间距离,若两点有公共边且都没有障碍,两点可达。
我们可以发现,问题的关键在于障碍物的处理。因为我们只需要找两点之间的最大距离,所以这个障碍物全都用来满足最大距离的情况就行了。
建图,把有障碍的地方距离建为,其它可达的建为。然后对于每个点,我们用(或者)求出其他点到它的最短距离,如果最短距离小于等于,说明我们可以通过移走障碍物把这两个点联通。然后更新一下最大值即可。

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 35;
const int  INF = 0x3f3f3f3f;
#define mp make_pair
#define pii pair<int,int>
string s[N];
int n,m,k,dis[N][N],vis[N][N],d[4][2]={1,0,0,1,-1,0,0,-1};
void spfa(int x,int y){
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            dis[i][j]=INF;
            vis[i][j]=0;
        }
    }
    queue<pii> q;
    q.push(mp(x,y));
    vis[x][y]=1;dis[x][y]=(s[x][y]=='1');
    while(!q.empty()){
        pii mid=q.front();q.pop();
        x=mid.first,y=mid.second;
        vis[x][y]=0;
        for(int i=0;i<4;i++){
            int dx=x+d[i][0],dy=y+d[i][1];
            if(dx<0||dx>=n||dy<0||dy>=m)    continue;
            if(dis[dx][dy]>dis[x][y]+(s[dx][dy]=='1')){
                dis[dx][dy]=dis[x][y]+(s[dx][dy]=='1');
                q.push(mp(dx,dy));
                vis[dx][dy]=1;
            }
        }
    }
}
int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<n;i++)    cin>>s[i];
    double ans=0;
    for(int a=0;a<n;a++){
        for(int b=0;b<m;b++){
            spfa(a,b);
            for(int c=0;c<n;c++){
                for(int d=0;d<m;d++){
                    if(dis[c][d]<=k){
                        ans=max(ans,sqrt((a-c)*(a-c)+(b-d)*(b-d)));
                    }
                }
            }
        }
    }
    printf("%.6lf\n",ans);
    return 0;
}