• 【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;
    } 
    
  • 相关阅读:
    【未完成0.0】Noip2012提高组day2 解题报告
    【数论+技巧】神奇的Noip模拟试题第二试 T1 素数统计
    Noip2014 提高组 T2 联合权值 连通图+技巧
    Noip2014 提高组 day1 T1· 生活大爆炸版石头剪刀布
    神奇的Noip模拟试题 T3 科技节 位运算
    博客小谈
    神奇的Noip模拟试题一试 2 排队
    神奇的Noip模拟试题第一试 合理种植 枚举+技巧
    使用Desktop App Converter打包桌面应用程序
    Rust Linking With C Library Functions
  • 原文地址:https://www.cnblogs.com/DexterYsw/p/7898480.html
Copyright © 2020-2023  润新知