2017.5 校內預選賽 A H
題目描述:
目前圖像識別是一項非常熱門的技術,最流行的莫不過是深度學習的圖像識別,識別率甚至能達到99%以上。當然,對於簡單的圖像來說,深度學習是沒有必要的。比如如果要識別安徽拼音的首字母A和H,就可以不用深度學習就可以判斷。現在有一些只含A或者H的圖像,你知道該如何識別嗎?
輸入描述:
第一行輸入正整數T,表示數據的組數。
每組數據中,第一行是兩個正整數n和m,表示圖像的大小。
接下來有n行,每行m個字符,只可能為‘.‘或者‘#‘。‘.‘表示白色,‘#‘表示黑色。‘#‘會通過上下左右或者左上左下右上右下連成一個區域,該區域表示字母。
數據保證字母在圖像內,不會有缺失。
數據保證圖像內只含有A或者H,且除字母外無其他黑色區域。不存在空白圖像或者含有其他內容的數據。
註意,字母不一定是正著的,有可能是斜著橫著或者倒著的。
特別提示:圖像一定是白底黑字的,不會存在反色的情況。
輸出描述
對於每行數據,輸出‘Case t: x‘,x表示你所識別出來的字母。
輸入樣例:
2
3 6
######
..#.#.
...#..
9 21
.....................
...###.......###.....
.....#.........#.....
.....#.........#.....
.....###########.....
.....#.........#.....
.....#.........#.....
...###.......###.....
.....................
輸出樣例:
Case 1: A
Case 2: H
…..#.#
….###
…#.#.
其實這個題目是我們參加安徽省程序設計大賽時候的一個題目,ljm學長又把這個題目放到校內預選賽中,算是其中的一個較為簡單的題目(ps: 團隊賽感覺比個人賽有趣)
我看見這個題目的思路還是想找A H 這連個字母有是不同,剛開始想到的還是A和H的兩個邊是不同的,H的兩個邊平行,A則相交,但是題目A 和 H 但有些樣例是不規則的形狀,這樣仔細想下去,會變得很復雜,所以得轉換下思路。那該怎麽辦呢?
其實可以註意到,A中有個用#圍起來的封閉區域,而H沒有,那怎麽找到這個區域,圖的遍歷,我用的是dfs。代碼如下:
#include<iostream> #include<memory.h> using namespace std; int dir1[4]={0,1,0,-1}; int dir2[4]={1,0,-1,0}; int f[100][100]; //表示是否遍歷過 char filed[100][100]; void dfs(int x,int y,int n,int m, int &flag){ //引用類型很重要 f[x][y]=1; for(int i=0;i<4;i++){ //從四個方向遞歸 int dx=x+dir1[i]; int dy=y+dir2[i]; if(dx<0 || dx>=n || dy<0 || dy>=m) //判斷是否越界 flag=1; else if(filed[dx][dy]==‘.‘ && f[dx][dy]==0) dfs(dx,dy,n,m,flag); } } bool solve(int n,int m){ for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(filed[i][j]==‘.‘ && f[i][j]==0){ //選 filed[i][j]==. 並且沒有訪問過的點進行搜索 我這裏用的是dfs 其實也可以用bfs int flag=0; dfs(i,j,n,m,flag); if(flag==0) return true; } } } return false; } int main(){ int t; cin>>t; for(int k=1;k<=t;k++){ memset(f,0,100*100); //每個樣例都重置一下f int n,m; //圖的大小 cin>>n>>m; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>filed[i][j]; } } if(solve(n,m)) cout<<"Case "<<k<<": "<<"A"<<endl; else cout<<"Case "<<k<<": "<<"H"<<endl; } }
解釋下:solve函數裏面兩個循環,對圖中的所有點進行以此if判斷,然後對值為‘.‘且沒有訪問過的點開始遍歷,下圖為栗子
從換紅線的那個點開始遍歷。那就進入dfs函數。看下面一段代碼:
for(int i=0;i<4;i++){ //從四個方向遞歸 int dx=x+dir1[i]; int dy=y+dir2[i]; if(dx<0 || dx>=n || dy<0 || dy>=m) //判斷是否越界 flag=1; else if(filed[dx][dy]==‘.‘ && f[dx][dy]==0) dfs(dx,dy,n,m,flag); }
i從0到3代表四個方向,得到下一步應該到的坐標dx dy 然後對dx dy 進行判斷,如歌超出0-n 0-m範圍,說明x,y 處於邊界,如上圖所代表的點,那就說明它所在區域不可能四周都被#圍住,這個點就是個出口。那麽就把它的flag置為1。
A中有一個區域被#圍起來,所以flag不會被置為1,還是0,所以在solve中對flag進行判斷,如果flag==0 為true 說明為A 直接返回true到主函數。問題得解
ps: 註意dfs中的參數是對flag的引用,大家可以把引用去掉看看有什麽結果。(有助於理解遞歸哦)
看了這篇題解不能理解的同學,可以花一個圖按照程序手動推演下這個程序。(可以後臺留言,盡量回復)
2017.5 校內預選賽 A H