【CODEFORCES】 C. Kamal-ol-molk's Painting

15 篇文章 0 订阅
4 篇文章 0 订阅

C. Kamal-ol-molk's Painting
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Rumors say that one of Kamal-ol-molk's paintings has been altered. A rectangular brush has been moved right and down on the painting.

Consider the painting as a n × m rectangular grid. At the beginning an x × y rectangular brush is placed somewhere in the frame, with edges parallel to the frame, (1 ≤ x ≤ n, 1 ≤ y ≤ m). Then the brush is moved several times. Each time the brush is moved one unit right or down. The brush has been strictly inside the frame during the painting. The brush alters every cell it has covered at some moment.

You have found one of the old Kamal-ol-molk's paintings. You want to know if it's possible that it has been altered in described manner. If yes, you also want to know minimum possible area of the brush.

Input

The first line of input contains two integers n and m, (1 ≤ n, m ≤ 1000), denoting the height and width of the painting.

The next n lines contain the painting. Each line has m characters. Character 'X' denotes an altered cell, otherwise it's showed by '.'. There will be at least one altered cell in the painting.

Output

Print the minimum area of the brush in a line, if the painting is possibly altered, otherwise print  - 1.

Sample test(s)
input
4 4
XX..
XX..
XXXX
XXXX
output
4
input
4 4
....
.XXX
.XXX
....
output
2
input
4 5
XXXX.
XXXX.
.XX..
.XX..
output
-1

题解:这一题我已经写吐了,从中午一直写到现在,代码写的又长又乱,思路也很杂,应该有更好的办法能解决,等过几天看了题解在补出来,先写下自己的做法。

以下几点是不合法的情况:

一、因为这是一把长方形的刷子,只能往下或者往右,所以如果我从这个图形的边界走(只往下或往右),一定可以组成一个封闭的图形。如果不行,则输出-1.

二、因为是刷子,所以整个图只有可能存在一个封闭的X区域,比如这种情况:

4 4 

XX..

XX..

XX..

...X

这样就是不行的,所以从第一个点广搜。搜完后如果还有没搜到的点,输出-1。


三、我们在边界上定义一种点叫做拐点,图中已画出,我们把line1上的拐点和line2上的拐点记录下来,这样,line1和line2同方向的拐点就是刷子的两个对角,如果存在一组对角的面积与前面的对角计算出来的面积不相等的话就输出-1。

接下来说说可能的情况

一、首先刷子可能没有拐弯,所以最后的情况就是矩形,我们找出矩形长宽的最小值就可以了。

二、刷子拐弯了,纳闷我们先找出两条线上的拐点,然后针对拐点的情况作分析。

 1、如果某一条线上只有一个拐点或拐点比另一条线上的少,且此时的形状不是矩形,那么另一条线上的第二个怪拐点一定是与之相对的对角(具体可以画画看,这里不说了....而且这个思路的本质是想知道刷子最初是向左还是向右)所以计算此时面积,然后计算后面对角的面积,如果不等,就输出-1,否则就是答案。(上面第三点)

2、如果两条线拐点相等,那么久不能判断刷子一开始是向左还是向右,所以都要算,如果两种情况有一种可以,那就是答案,如果都不行,那就输出-1。

哗啦一大堆也不知道说清楚了没.....等过几天思路更加清晰了再补回来....

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

char s[1005][1005];
int n,m,h1,h2,ans,flag[1005][1005];

struct line
{
    int x,y;
} ;

struct line first[1000005],second[1000005],q[1000005];

void bfs(int x,int y)
{
    memset(flag,0,sizeof(flag));
    int h=0,t=0;
    q[t].x=x; q[t].y=y; t++;
    flag[x][y]=1;
    while (h!=t)
    {
        if (s[q[h].x+1][q[h].y]=='X' && flag[q[h].x+1][q[h].y]==0)
        {
            q[t].x=q[h].x+1; q[t].y=q[h].y; t++;
            flag[q[h].x+1][q[h].y]=1;
        }
        if (s[q[h].x][q[h].y+1]=='X' && flag[q[h].x][q[h].y+1]==0)
        {
            q[t].x=q[h].x; q[t].y=q[h].y+1; t++;
            flag[q[h].x][q[h].y+1]=1;
        }
        h++;
    }
}

int Right(int x,int y)
{
    if (s[x][y+1]=='X') return 1;
    else return 0;
}

int Down(int x,int y)
{
    if (s[x+1][y]=='X') return 1;
    else return 0;
}

int NO_Way(int x,int y)
{
    if (s[x+1][y]!='X' && s[x][y+1]!='X') return 1;
    else return 0;
}

int construct()
{
    int x,y,i,j,f=0;
    for ( i=0;i<n;i++)
    {
        for ( j=0;j<m;j++) if (s[i][j]=='X')
        {
            x=i; y=j; f=1;
            break;
        }
        if (f) break;
    }
    i=x; j=y; f=0;
    bfs(x,y);
    for (int i=0;i<n;i++)
        for (int j=0;j<m;j++)
        if (s[i][j]=='X' && !flag[i][j]) return 0;
    while (Right(i,j)) j++;
    first[h1].x=i; first[h1].y=j; h1++; f=1;
    while (!NO_Way(i,j))
    {
        if (Down(i,j))
        {
            if (!f) { first[h1].x=i; first[h1].y=j; h1++; f=1; }
            i++;
        }
        while (Right(i,j))
        {
            if (f) { first[h1].x=i; first[h1].y=j; h1++; f=0; }
            j++;
        }
    }
    int x1=i,y1=j;
    i=x;  j=y;
    while (Down(i,j)) i++; f=0;
    second[h2].x=i; second[h2].y=j; h2++; f=1;
    while (!NO_Way(i,j))
    {
        if (Right(i,j))
        {
            if (!f) { second[h2].x=i; second[h2].y=j; h2++; f=1; }
            j++;
        }
        while(Down(i,j))
        {
            if (f) { second[h2].x=i; second[h2].y=j; h2++; f=0; }
            i++;
        }
    }
    //check
    if (x1!=i || y1!=j) return 0;
    else return 1;
}

int area(int i,int j)
{
    int h=abs(first[i].x-second[j].x)+1;
    int w=abs(first[i].y-second[j].y)+1;
    return h*w;
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;i++)
        scanf("%s",s[i]);
    if (!construct())
    {
        cout <<-1<<endl;
        return 0;
    }
    //Rectangle
    if (h1==h2 && h1==1)
    {
        cout <<min(abs(first[0].x-second[0].x)+1,abs(first[0].y-second[0].y)+1)<<endl;
        return 0;
    }
    if (h1==1 || h1<h2)
    {
        ans=area(0,1);
        for (int i=0;i<h1;i++) if (ans!=area(i,i+1))
        {
            cout <<-1<<endl;
            return 0;
        }
    }
    else if (h2==1 || h2<h1)
    {
        ans=area(1,0);
        for (int i=0;i<h2;i++) if (ans!=area(i+1,i))
        {
            cout <<-1<<endl;
            return 0;
        }
    }
    else
    {
        int k1=0,k2=0;
        ans=area(0,1);
        for (int i=0;i<h1-1;i++) if (ans!=area(i,i+1)) {k1=1; break;}
        ans=area(1,0);
        for (int i=0;i<h2-1;i++) if (ans!=area(i+1,i)){k2=1; break;}
        if (k1 && k2)
        {
            cout <<-1<<endl;
            return 0;
        }
        else if (!k1 && !k2) ans=min(area(1,0),area(0,1));
        else if (!k1) ans=area(0,1);
        else if (!k2) ans=area(1,0);
    }
    cout <<ans<<endl;
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值