Codeforces Round #501 (Div. 3) E2 - Stars Drawing (Hard Edition)(dp,前綴和,覆蓋)

        題目鏈接: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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章