1. 程式人生 > >【bzoj1298】:[SCOI2009]最長距離

【bzoj1298】:[SCOI2009]最長距離

mage stream 如果 fin tor size stdin front sqrt

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;
} 

【bzoj1298】:[SCOI2009]最長距離