1. 程式人生 > >luogu P4961 小埋與掃雷

luogu P4961 小埋與掃雷

題目背景

小埋總是在家中打遊戲,一天,她突然想玩Windows自帶的掃雷,在一旁的哥哥看見了,想起了自己小時候資訊課在機房玩掃雷的日子,便興致勃勃地開始教小埋掃雷。然而,小埋還是不明白 每局將所有非雷的方塊點開所需最少左鍵點選數,參見掃雷網的教程 )怎麼算,於是她找到了你。

題目描述

小埋會告訴你一盤掃雷,用一個n×m 的矩陣表示,1 是雷 ,0 不是雷,請你告訴她這盤掃雷的 3bv 。

周圍八格沒有“雷”且自身不是“雷”的方格稱為“空格”,周圍八格有“雷”且自身不是“雷”的方格稱為“數字”,由“空格”組成的八連通塊稱為一個“空”。 3bv= 周圍八格沒有“空格”的“數字”個數++“空"的個數。

如果看不懂上面的計算方式,可以看題目背景中給出的教程,或者看下面的樣例解釋。

注:八連通

輸入輸出格式

輸入格式:
第一行有兩個整數 n 和 m,代表這盤掃雷是一個 n×m 的矩陣。

後面的 n 行每行有 m 個整數,表示這個矩陣,每個數字為 0 或1,1 代表是雷,0 代表不是雷。

輸出格式:
一個整數,代表這盤掃雷的 3bv 。

輸入輸出樣例

輸入樣例#1: 複製
8 8
0 0 0 1 1 0 0 0
1 0 0 1 0 0 0 1
1 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0
輸出樣例#1: 複製
13
說明

1≤n, m≤1000

 首先解釋一下3bv,一個點會顯示出四周8個點中有幾個雷,對於一個3bv即為值為0的點聯通塊(同時聯通塊周圍的所有點也視為在這個3bv內)或一個不屬於任一聯通塊的一個四周有雷的點,(1,1)(1,2)(1,3)(2,2)(2,3)........這些都是
這樣其是很容易就可以聯想到一個很經典的問題填充顏色, 對於零的聯通塊進行dfs填充顏色,在填充的時候可以可以記錄塊的個數,最後剩下的塊就是雷與距離3bv所差的塊數,所以可以減去3bv = 0的聯通塊數 + n*m - 聯通塊一共所佔的塊數(包括0的聯通塊周圍的那些塊) - 雷的數目;這個問題就這樣解決了。

貼程式碼:


#include<iostream>
#include<cstdio>
using namespace std;
inline int read(){
    int x = 0;int f = 1;char c = getchar();
    while(c<'0'||c>'9'){
        if(c == '-')f = -f;
        c = getchar();
    }
    while(c<='9' && c>='0'){
        x = x*10 + c - '0';
        c = getchar();
    }
    return x*f;
}
int n,m,ans,tot,cnt;
int pic[2000][2000];
void dfs(int x,int y){
    if(x <= n&&x >= 1 && y <= m&& y >= 1&&pic[x][y] == 0){
       pic[x][y] = -1;
       cnt++;
       dfs(x+1,y);
       dfs(x,y+1);
       dfs(x,y-1);
       dfs(x-1,y);
       dfs(x + 1,y+1);
       dfs(x + 1,y-1);
       dfs(x-1,y-1);
       dfs(x-1,y+1);
    }
    else if(x <= n&&x >= 1 && y <= m&& y >= 1&&pic[x][y]==9&&(pic[x-1][y]==-1||pic[x+1][y]==-1||pic[x][y+1]==-1||pic[x][y-1]==-1)){
        pic[x][y] = -1; 
        cnt++;
    }
}
int main(){
    n = read(); m = read();
    for(int i = 1; i<= n;i++) {
        for(int j = 1; j<=m; j++){
            pic[i][j] = read();
            if(pic[i][j] == 1)tot++;
        }
    }
    for(int i = 1; i<=n; i++){
        for(int j = 1; j<=m; j++){
            if(pic[i][j] == 1){
                if(pic[i+1][j] != 1)pic[i+1][j] = 9;
                if(pic[i][j+1] != 1)pic[i][j+1] = 9;
                if(pic[i][j-1] != 1)pic[i][j-1] = 9;
                if(pic[i-1][j] != 1)pic[i-1][j] = 9;
                if(pic[i+1][j+1] != 1)pic[i+1][j+1] = 9;
                if(pic[i+1][j-1] != 1)pic[i+1][j-1] = 9;
                if(pic[i-1][j+1] != 1)pic[i-1][j+1] = 9;
                if(pic[i-1][j-1] != 1)pic[i-1][j-1] = 9; 
            }
        }
    } 
    for(int i = 1; i<=n;i ++){
        for(int j = 1; j<=m; j++){
            if(pic[i][j] == 0){
                dfs(i,j);/*
                for(int  k = 1; k<=n; k++){
                    for(int p = 1; p<=m ;p++){
                        cout<<pic[k][p]<<' ';
                    }
                    cout<<'\n';
                }
                cout<<cnt<<'\n';*/
                ans++;
            }
        } 
    }
    printf("%d ",ans+n*m-cnt-tot);
    return 0;
}