【bzoj1298】:[SCOI2009]最长距离

1295: [SCOI2009]最长距离

              Time Limit: 10 Sec  Memory Limit: 162 MB

Description

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

Input

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

Output

输出文件maxlength.out包含一个浮点数,保留6位小数。

Sample Input

【输入样例一】
3 3 0
001
001
110

【输入样例二】
4 3 0
001
001
011
000

【输入样例三】

3 3 1
001
001
001

Sample Output

【输出样例一】
1.414214

【输出样例二】
3.605551

【输出样例三】
2.828427

HINT

20%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 0 。 40%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 2 。 100%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 30 。

Solution

题目大意说简单点就是让你可以将 t 个黑块变成白块,然后问最大的可能的两点长度是多少

说实话,我这么菜的人...觉得这个题好劲...%%%%cxy说不就是个死怕发吗%%%%

首先可以从题目的操作来看,将黑块变成白块的目的是让更多的白块相连通,让更多的白块联通就是让答案更大

即花费一个代价让答案变大点或不改变...

然后 联通块 我们肯定要先dfs找出所有的联通块然后再搞搞。

对于一个黑点我们可以让他独立为一个联通块然后用一个数组记录此块的权值为 1(经过这个黑点就是用了一次机会)。

这个权值的意义在于,我们不用考虑去改变那些黑块,我们只需要计算路径的时候看有多少黑块被统计(跑最短路!)

然后我们就可以跑出任意两个联通块使他们联通的最小代价

最后我们只能统计代价 <= t 的答案即可

不知道是这个模型我没怎么见过还是怎么的 我觉得很美妙....

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>
#define maxn 1010
#define inf 1e9
using namespace std;

vector<int>G[maxn];
int n,m,t,num;
char mp[35][35];
bool vis[maxn];
int dis[maxn][maxn],d[maxn][maxn],c[maxn],flag[35][35];
int dx[]{0,0,1,-1},dy[]{1,-1,0,0};

inline void dfs(int x,int y){
	flag[x][y]=num;
	if(mp[x][y]=='1')return void(c[num]=1);
	for(int i=0;i<4;i++){
		int tx=x+dx[i],ty=y+dy[i];
		if(tx<1||tx>n||ty<1||ty>m||flag[tx][ty]||mp[tx][ty]=='1')continue;
		dfs(tx,ty);
	}
}

inline void spfa(int s){
	queue<int>q;
	for(int i=1;i<=num;i++)d[s][i]=inf;
	d[s][s]=c[s];q.push(s);
	while(!q.empty()){
		int k=q.front();q.pop();vis[k]=false;
		for(int i=0;i<G[k].size();i++){
			int kk=G[k][i];
			if(d[s][kk]<=d[s][k])continue;
			d[s][kk]=d[s][k]+c[kk];
			if(!vis[kk])vis[kk]=true,q.push(kk);
		}
	}
}

int main(){
#ifdef YSW 	
	freopen("in.txt","r",stdin);
#endif
	scanf("%d%d%d",&n,&m,&t);
	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++)
			if(!flag[i][j])num++,dfs(i,j);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int k=1;k<=n;k++)
				for(int l=1;l<=m;l++){
					int u=flag[i][j],v=flag[k][l];
					dis[u][v]=max(dis[u][v],(i-k)*(i-k)+(j-l)*(j-l));
				}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			int cur=flag[i][j];
			for(int k=0;k<4;k++){
				int tx=i+dx[k],ty=j+dy[k];
				if(tx<1||tx>n||ty<1||ty>m||cur==flag[tx][ty])continue;
				G[cur].push_back(flag[tx][ty]);
			}
		}
	int ans=-1;
	for(int i=1;i<=num;i++)spfa(i);
	for(int i=1;i<=num;i++)
		for(int j=1;j<=num;j++){
			if(d[i][j]<=t)ans=max(ans,dis[i][j]);
		}
	printf("%.6f",sqrt(ans));
	return 0;
} 
原文地址:https://www.cnblogs.com/DexterYsw/p/7898480.html