#include #include #include #include #include #include #include using namespace std;int n, m;char a[1005][1005];//储存字符int b[1005][1005];//字符转化为数字,‘#’为1,其它为0int vis[1005][1005];int sum[1005][1005];//统计左上角到当前位置总数,用于判断一个矩形是否是全为1的矩形queue <pair > q;int ans;//存放结果,符合条件矩形个数int mini, minj, maxi, maxj;//一块连通区域的左上角与右下角(如果确实是符合条件的矩形的话)void bfs()//广度搜索,找连通都是1的区域{ int ai[4] = {-1, 0, 1, 0}; int aj[4] = {0, 1, 0, -1}; while(!q.empty()) { pair tmp=q.front(); q.pop(); int j = tmp.first; int k = tmp.second; for (int i=0; i<4; i++) { if (((j+ai[i])<=0)||((j+ai[i])>n)||((k+aj[i])<=0)||((k+aj[i])>m)) continue;//越界 else if (vis[j+ai[i]][k+aj[i]]) continue;//已被访问 else if (!b[j+ai[i]][k+aj[i]])//为0,所以不符合,标记为访问过,跳过 { vis[j+ai[i]][k+aj[i]] = 1; continue; } else//符合条件加入队列 { vis[j+ai[i]][k+aj[i]] = 1; q.push(make_pair(j+ai[i], k+aj[i])); minj = min(k+aj[i], minj); maxj = max(k+aj[i], maxj); mini = min(j+ai[i], mini); maxi = max(j+ai[i], maxi); } } }}int main(){ while(~scanf("%d %d",&n,&m)) { ans = 0; memset(a, 0, sizeof a); memset(b, 0, sizeof b); memset(sum, 0, sizeof sum); memset(vis, 0, sizeof vis); for (int j=0; j<n; j++) { scanf("%s", a[j]); } for (int j=1; j<=n; j++) { for (int k=1; k<=m; k++) { if (a[j-1][k-1]=='#') b[j][k] = 1; else b[j][k] = 0; sum[j][k] = sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1]+b[j][k]; //统计左上角到当前位置总数,用于判断一个矩形是否是全为1的矩形 } } int flag = 0; for (int j=1; j<=n; j++) { for (int k=1; k<=m; k++) { if (vis[j][k]) continue; if (!b[j][k]) { vis[j][k] = 1; continue; } while(!q.empty()) q.pop(); q.push(make_pair(j, k)); mini=maxi=j; minj=maxj=k; bfs(); int temp = sum[maxi][maxj]-sum[mini-1][maxj]-sum[maxi][minj-1]+sum[mini-1][minj-1]; //(mini, minj)到(maxi, maxj)的矩形如果都为1的值理想值与现实值的比较 if (temp==(maxi-mini+1)*(maxj-minj+1)) ans++; else { flag=1; break; } } if (flag) break; } if (flag) printf("So Sad\n"); else printf("There are %d ships.\n", ans); } return 0;}