題目鏈接:http://codeforces.com/contest/1015/problem/E2
題目大意,給你一個n×m大小的字符矩陣,僅由‘.’和‘*’組成,提問這個圖可否劃分爲一些由‘*’組成的十字形狀,這些十字之間可以有重疊,如果可以完全覆蓋輸出每個十字中心座標與邊長度,不可以輸出-1。
input 6 8 ....*... ...**... ..*****. ...**... ....*... ........ |
input 5 5 .*... ****. .**** ..**. ..... |
input 5 5 .*... ***.. .*... .*... ..... |
input 3 3 *.* .*. *.* |
output 3 3 4 1 3 5 2 3 5 1 |
output 3 2 2 1 3 3 1 3 4 1 |
output -1 |
output -1 |
這是一道很有意思的題,在這場比賽中上一道題是這一道題的簡化版本,數據範圍僅有100,所以我採用了O(n^3)的做法,即枚舉每個 * ,然後向四周擴展,顯然,在這道題中1000的數據範圍中這種做法會超時。
正確的做法類似與dp,首先開四個與字符數組相同大小的數組l,r,up,dn,然後進行兩次掃描,這四個數組分別代表了從左邊、右邊、上邊、下邊開始數,數到當前位置的星號時已經有幾個星號。然後再次掃描,枚舉每一個星號,每一個星號上取l(i,j),
r(i,j),up(i,j),dn(i,j)中的最小值min(i,j),代表已當前位置爲中心可能形成的最大十字,當min>1時代表當前十字合法。用一個vector記錄下答案,掃一遍就可以找到所有十字。同時在開兩個數組judgex與judgey,同樣與字符數組一樣大小,將十字一橫中第一個格子judgex(i,j-min+1)加上一,將橫中最後一個格子的下一個格子judgex(i,j+min)的值減一,同理將十字一豎中第一個格子judgey(i-min+1,j)加上一,將橫中最後一個格子的下一個格子judgex(i+min,j)的值減一,同時分別對這兩個數組求橫向與縱向的前綴和,由此可以發現我們找的答案的十字中覆蓋的值都大於0。
再進行一次掃描,如果圖中當前位置爲星號,且judgex與judgey的當前數值都爲0,說明該星號不能被我們找到的答案中的十字中的任何一個覆蓋,也就說明當前圖不能完全被十字覆蓋,不合法,輸出-1,否則輸出vector中記錄下的答案。
下面爲代碼
#include <bits/stdc++.h>
using namespace std;
#define debug cout<<"???"<<endl
#define sync std::ios::sync_with_stdio(false)
#define ll long long
#define pb push_back
#define mp make_pair
#define MAXN 100005
#define INF 0x3f3f3f3f
#define frein freopen("input.txt", "r", stdin)
#define freout freopen("output.txt", "w", stdout)
char g[1005][1005];
int l[1005][1005],r[1005][1005],up[1005][1005],dn[1005][1005];
int jx[1005][1005],jy[1005][1005];
int n,m;
struct ans
{
int x,y;
int len;
};
vector <ans> p;
int main()
{
//sync;
//frein;
//freout;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",g[i]+1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='*'){
l[i][j]=l[i][j-1]+1;
up[i][j]=up[i-1][j]+1;
}
}
}
for(int i=n;i>=1;i--){
for(int j=m;j>=1;j--){
if(g[i][j]=='*'){
r[i][j]=r[i][j+1]+1;
dn[i][j]=dn[i+1][j]+1;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='*'){
int len=INF;
len=min(min(l[i][j],r[i][j]),
min(up[i][j],dn[i][j]));
if(len>1){
ans temp;
temp.x=i;
temp.y=j;
temp.len=len-1;
p.pb(temp);
jx[i-len+1][j]++;
jx[i+len][j]--;
jy[i][j-len+1]++;
jy[i][j+len]--;
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
jx[i][j]+=jx[i-1][j];
jy[i][j]+=jy[i][j-1];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='*'&&jx[i][j]==0&&jy[i][j]==0){
printf("-1\n");
return 0;
}
}
}
int size=p.size();
printf("%d\n",size);
for(int i=0;i<size;i++){
printf("%d %d %d\n",p[i].x,p[i].y,p[i].len);
}
return 0;
}