1. 程式人生 > >Ancient Messages UVA - 1103

Ancient Messages UVA - 1103

會有 row 集合 訪問 並排 [] 下標 amp vector

題目鏈接:https://vjudge.net/problem/UVA-1103

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

題目大意:每組數據包含H行W列的字符矩陣(H<=200,W<=50) 每個字符為為16進制 你需要把它轉化為二進制。 轉化為二進制之後 1代表黑點 0代表白點

問你出現的所有符號 並按字典序輸出!

思路:首先看到這道題,完全沒看懂題意 ,真的沒看懂,後來搜了題解才看明白題意,但是還是不會做,這道題是在紫書上看到的,紫書上並沒有給出代碼,學了別人的博客!

好了 具體怎麽做呢?

仔細觀察可以發現,每個字符中出現的圓是不一樣的,看一道題,很多時候就是找特征量,用特征量來區分題目中的量! 這題的特征量就是每個字符中圓的個數了! 讀者仔細看一下圖就能明白了

然後我們知道了特征量是圓 所以我們求得該圖形有多少個圓是不是就知道了是哪個圖形呢? 當然是的

但是問題來了,怎麽求得圖形內有多少個圓呢? 我也想了很久 ,這個到底怎麽控制,首先你得知道那些白點是不是構成圓,而且這些圓還要在黑色像素之內。 感覺完全沒有思路呀

註意題目中說了,兩個圖形並不會相接觸,這就很重要了,不會相接觸,那麽我們想一下,當我們知道了一條黑色曲線,是不是與它相接觸的白點就是圓環? 有人可能會說,不一定吧 也可能不構成圓環啊

是的 ,的確有可能,不構成圓環的話肯定是最外圍的那一些白色點,我們把這些點連成一個連通塊,考慮情況的時候把它忽略就行了。 所以要解決這道題的關鍵就是分析上面內容了

其他的就是求連通塊,註意黑色連通塊要存起來,因為我們是通過黑色連通塊來尋找有多少個白色圓環的 到這這道題就解決了

看代碼:

#include<iostream>
#include<vector>
#include<set>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxh=200+5;
const int maxw=50*4+5;
char bin[256][5];
int H,W,pic[maxh][maxw],color[maxh][maxw];
char line[maxw]; //pic[i][j] i j 從1開始 void decode(char ch,int row,int col) { for(int i=0;i<4;i++) { pic[row][col+i]=bin[ch][i]-0; } } const int dr[]={-1,1,0,0}; const int dc[]={0,0,-1,1}; void dfs(int row,int col,int c)//把屬於一個連通塊的歸為一個color值 { color[row][col]=c;//該位置標記為訪問過 for(int i=0;i<4;i++) { int row2=row+dr[i]; int col2=col+dc[i]; //是否為合法的位置 if(row2>=0&&row2<H&&col2>=0&&col2<W&&pic[row2][col2]==pic[row][col]&&color[row2][col2]==0)//是否為相等的元素 { dfs(row2,col2,c); } } } vector<set<int> >neighbors; //這裏set集合的確用的好 這樣就不會有重復的白色塊了 !!! void check_neighbors(int row,int col) { for(int i=0;i<4;i++) { int row2=row+dr[i]; int col2=col+dc[i];//color 為1 代表是最外圍的白色部分 並不是圈 if(row2>=0&&row2<H&&col2>=0&&col2<W&& pic[row2][col2]==0&&color[row2][col2]!=1) neighbors[color[row][col]].insert(color[row2][col2]); } } /* Ankh: A 1個 Wedjat: J 3個 Djed: D 5個 Scarab: S 4個 Was: W 0個 Akhet: K 2個 */ const char* code="WAKJSD";//以有多少個圈來排序 剛好是012345個 //以容器長度來表示黑連通塊旁的內白連通塊數 char recognize(int c) { int cnt=neighbors[c].size();//該黑色連通塊有周圍有多少個白圈 return code[cnt]; } int main() { strcpy(bin[0],"0000");//這裏相當於bin[i] i是字符1的ascii碼 strcpy(bin[1],"0001"); strcpy(bin[2],"0010"); strcpy(bin[3],"0011"); strcpy(bin[4],"0100"); strcpy(bin[5],"0101"); strcpy(bin[6],"0110"); strcpy(bin[7],"0111"); strcpy(bin[8],"1000"); strcpy(bin[9],"1001"); strcpy(bin[a],"1010"); strcpy(bin[b],"1011"); strcpy(bin[c],"1100"); strcpy(bin[d],"1101"); strcpy(bin[e],"1110"); strcpy(bin[f],"1111"); int ca=0; while(cin>>H>>W) { if(H==0&&W==0) break; memset(pic,0,sizeof(pic)); for(int i=0;i<H;i++) { scanf("%s",line); for(int j=0;j<W;j++) { decode(line[j],i+1,j*4+1);//轉換為對應的二進制 } } H+=2;//這兩步是為何 為何要加2???難道是把原來的包圍起來??? W=W*4+2;//是的 如果不這樣的話 不能保證最外圍的白色一定是1 int cnt=0;//存有多少個連通塊 vector<int> cc;//存所有黑色連通塊 memset(color,0,sizeof(color));//標記數組 for(int i=0;i<H;i++) { for(int j=0;j<W;j++) { if(!color[i][j])//沒有標記過 { dfs(i,j,++cnt); if(pic[i][j]==1) cc.push_back(cnt);//掃描矩陣 且為所有連通塊編號 並把黑連通塊存進cc容器中 } } } neighbors.clear(); neighbors.resize(cnt+1);//設置容器大小 原來這步是不能少的 !! 少了的話 neighbors[i] 就出錯了!! 切記!! for(int i=0;i<H;i++)//再掃描一遍?? { for(int j=0;j<W;j++) { if(pic[i][j]==1) check_neighbors(i,j);//掃描黑點 並把該點旁邊有幾個內連通白塊存入neighbors容器 其實下標為黑點對應的連通塊編號 } } vector<char>ans; for(int i=0;i<cc.size();i++)//遍歷所有的黑色連通塊 ans.push_back(recognize(cc[i]));//存目標值 並排序 sort(ans.begin(),ans.end()); printf("Case %d: ",++ca); for(int i=0;i<ans.size();i++) printf("%c",ans[i]); printf("\n"); } return 0; }

Ancient Messages UVA - 1103