CodeForces - 616C詳解(很有意思的bfs)
阿新 • • 發佈:2018-12-28
思路:
很有意思的一道題,首先如果暴力遍歷"*",bfs(),執行到第11個測試點就超時了,因為點比較多,是1000*1000的格子,每次bfs一個點要進行4*10^6次運算(4是因為要上下左右找一次)。也就是最大運算是10^6*4*10^6等於4*10^12,遠超出計算機一次能運算的10^8.
正確思路:
遍歷" . ",把"."的連通區域bfs出來,給它賦上標記,表明這些點是一個連通區域,然後記錄這個連通區域的點個數,將標記與點個數作為一對存入map中,
這樣我們可以得到所有的連通區域(兩個連通區域不相接),對於每一個" * "來說,把它周圍四個方位的點所在的連通區域的點的個數加起來再加1就是總的連通點。但此時可能會有重複的點被算進來了,因為" * "的周圍的點可能就是同一個連通區域,所以,
我們採用set集合,把"*"周圍的點的標記放進去去重。
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #include<vector> #include<map> #include<set> #include<algorithm> using namespace std; int n,m; int dx[4]={1,-1,0,0}; int dy[4]={0,0,1,-1}; int vis[1050][1050]; char mk[1050][1050]; struct node{ int x,y; }nextt; map<int,int> mm; queue<node> q; set<int> ss; set<int>::iterator it; bool check(int x,int y){ if(x<0||x>=n||y<0||y>=m) return 0; if(vis[x][y]) return 0; if(mk[x][y]!='.') return 0; return 1; } void bfs(int sx,int sy,int ans){ int cnt=0; node p; p.x=sx,p.y=sy; q.push(p); vis[sx][sy]=ans; while(!q.empty()){ node temp=q.front(); q.pop(); cnt++; for(int i=0;i<4;i++){ nextt.x=temp.x+dx[i]; nextt.y=temp.y+dy[i]; if(check(nextt.x,nextt.y)){ vis[nextt.x][nextt.y]=ans; q.push(nextt); } } } mm[ans]=cnt;//把同屬於一個連通域的'.'個數放入map中 } int main(){ int sum=0; scanf("%d %d",&n,&m); memset(vis,0,sizeof(vis)); int cc=1; for(int i=0;i<n;i++) scanf("%s",mk[i]); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(mk[i][j]=='.'&&!vis[i][j]) bfs(i,j,cc++); } } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(mk[i][j]=='*'){ sum=1; ss.clear(); if(i>0) ss.insert(vis[i-1][j]); if(i<n-1) ss.insert(vis[i+1][j]); if(j>0) ss.insert(vis[i][j-1]); if(j<m-1) ss.insert(vis[i][j+1]); for(it=ss.begin();it!=ss.end();it++){ sum+=mm[*it]; } sum%=10; mk[i][j]=sum+'0'; } } } for(int i=0;i<n;i++){ printf("%s\n",mk[i]); } return 0; }