NEU1682 全球变暖(bfs+dfs)

February 07, 2016

题目链接

中文题。有两种方法:

第一种:枚举所有海洋的点,bfs 搜索,标记陆地的点是第几天被淹没,然后 DFS 连通分量。

#include<iostream>
#include<cmath>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
int n, m, t;
int pic[2005][2005];
int vis[2005][2005];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
bool judge(int x, int y){
    if(x>=0 && x<n && y>=0 && y<m)
        return true;
    else return false;
}
void dfs(int x, int y, int cnt){
    if(!judge(x, y) || vis[x][y] || !pic[x][y]) return;
    vis[x][y] = 1;
    for(int i = 0; i < 4; i++){
        int x1 = x+dir[i][0];
        int y1 = y+dir[i][1];
        dfs(x1, y1, cnt);
    }
}
int main(){
    //freopen("a.txt", "r", stdin);
    while(scanf("%d %d %d", &n, &m, &t) != EOF){
        queue<int> q;
        for(int i = 0; i < n; i++){
            char ch[2005];
            scanf("%s", ch);
            for(int j = 0; j < m; j++){
                if(ch[j] == '#')
                    pic[i][j] = -1;
                else{
                    q.push(i*m+j);
                    pic[i][j] = 0;
                }
            }
        }
        for(int i = 0; i < n; i++){
            if(pic[i][0] == -1){
                pic[i][0] = 1;
                q.push(i*m);
            }
            if(pic[i][m-1] == -1){
                pic[i][m-1] = 1;
                q.push(i*m+m-1);
            }
        }
        for(int i = 0; i < m; i++){
            if(pic[0][i] == -1){
                pic[0][i] = 1;
                q.push(i);
            }
            if(pic[n-1][i] == -1){
                pic[n-1][i] = 1;
                q.push(m*(n-1)+i);
            }
        }
        while(!q.empty()){
            int f = q.front();
            q.pop();
            int x = f/m; int y = f%m;
            for(int i = 0; i < 4; i++){
                int x1 = x+dir[i][0];
                int y1 = y+dir[i][1];
                if(judge(x1, y1) && pic[x1][y1] == -1){
                    pic[x1][y1] = pic[x][y]+1;
                    q.push(x1*m+y1);
                }
            }
        }
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(pic[i][j] <= t)
                    pic[i][j] = 0;
        memset(vis, 0, sizeof(vis));
        int num = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(pic[i][j] && !vis[i][j])
                    dfs(i, j, ++num);
        cout << num <<endl;
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(!pic[i][j])
                    cout << ".";
                else cout << "#";
            }
            cout << endl;
        }

    }
    return 0;
}

用 queue 写 bfs 的话 1.7s 过的,如果用数组搞 bfs 只有 0.7s,差距非常感人。

第二种方法:在搜索连通分量之前,并不需要 bfs,正反各遍历一遍图,就可以标记完成。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
int dis[4][2]={ {0,1},{0,-1},{1,0},{-1,0}};
char mp[2010][2010];
int TM[2010][2010];
bool vis[2010][2010];
int m,n,t;
struct mm{
    int x,y;
};
void bfs(int x,int y){
    queue <mm> q;
    mm st;
    st.x=x;
    st.y=y;
    vis[x][y]=1;
    q.push(st);
    while(!q.empty()){
        mm now=q.front();
        q.pop();
        mm next;
        for(int i=0;i<4;i++){
            next.x=now.x+dis[i][0];
            next.y=now.y+dis[i][1];
            if(!vis[next.x][next.y]&&TM[next.x][next.y]>t){
                vis[next.x][next.y]=1;
                q.push(next);
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&n,&m,&t)!=EOF){
        memset(vis,0,sizeof(vis));
        memset(TM,0,sizeof(TM));
        for(int i=0;i<n;i++){
            scanf("%s",mp[i]);
        }
        for(int j=0;j<m;j++){
            if(mp[0][j]=='.'){
                TM[0][j]=0;
            }
            else{
                TM[0][j]=1;
            }
            mp[0][j]='.';
            if(mp[n-1][j]=='.'){
                TM[n-1][j]=0;
            }
            else{
                TM[n-1][j]=1;
            }
            mp[n-1][j]='.';
        }
        for(int i=1;i<n-1;i++){
            if(mp[i][0]=='.'){
                TM[i][0]=0;
            }
            else{
                TM[i][0]=1;
            }
            mp[i][0]='.';
            if(mp[i][m-1]=='.'){
                TM[i][m-1]=0;
            }
            else{
                TM[i][m-1]=1;
            }
            mp[i][m-1]='.';
        }
        for(int i=1;i<n-1;i++){
            for(int j=1;j<m-1;j++){
                if(mp[i][j]=='.'){
                    TM[i][j]=0;
                }
                else{
                    int k=1000000;
                    k=min(k,TM[i-1][j]+1);
                    //k=min(k,TM[i+1][j]+1);
                    k=min(k,TM[i][j-1]+1);
                    //k=min(k,TM[i][j+1]+1);
                    TM[i][j]=k;
                    //printf("%d %d %dn",i,j,k);
                }
            }
        }
        /*for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                printf("%d",TM[i][j]);
            }
            printf("n");
        }*/
        for(int i=n-2;i>0;i--){
            for(int j=m-2;j>0;j--){
                if(mp[i][j]=='.'){
                    TM[i][j]=0;
                }
                else{
                    int k=1000000;
                    k=min(k,TM[i-1][j]+1);
                    k=min(k,TM[i+1][j]+1);
                    k=min(k,TM[i][j-1]+1);
                    k=min(k,TM[i][j+1]+1);
                    TM[i][j]=k;
                }
            }
        }
        int ans=0;
        for(int i=1;i<n-1;i++){
            for(int j=1;j<m-1;j++){
                if(!vis[i][j]&&mp[i][j]=='#'&&TM[i][j]>t){
                    ans++;
                    bfs(i,j);
                }
            }
        }
        /*for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                printf("%d",TM[i][j]);
            }
            printf("n");
        }*/
        printf("%dn",ans);
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(TM[i][j]<=t){
                    printf(".");
                }
                else{
                    printf("#");
                }
            }
            printf("n");
        }
    }
    return 0;
}

第二种方法只有 0.5s


Profile picture

Written by Armin Li , a venture capitalist. [Weibo] [Subscribe]