【UVa12265】Selling Land 贩卖土地

题目描述

As you may know, the country of Absurdistan is full of abnormalities. For example, the whole country can be divided into unit squares that are either grass or swamp. Also, the country is famous for its incapable bureaucrats. If you want to buy a piece of land (called a parcel), you can only buy a rectangular area, because they cannot handle other shapes. The price of the parcel is determined by them and is proportional to the perimeter of the parcel, since the bureaucrats are unable to multiply integers and thus cannot calculate the area of the parcel. Per owns a parcel in Absurdistan surrounded by swamp and he wants to sell it, possibly in parts, to some buyers. When he sells a rectangular part of his land, he is obliged to announce this to the local bureaucrats. They will rst tell him the price he is supposed to sell it for. Then they will write down the name of the new owner and the coordinates of the south-east corner of the parcel being sold. If somebody else already owns a parcel with a south-east corner at the same spot, the bureaucrats will deny the change of ownership. Per realizes that he can easily trick the system. He can sell overlapping areas, because bureaucrats only check whether the south-east corners are identical. However, nobody wants to buy a parcel
containing swamp.

Now Per would like to know how many parcels of each perimeter he needs to sell in order to maximize his pro t. Can you help him? You may assume that he can always nd a buyer for each piece of land, as long as it doesn’t contain any swamps. Also, Per is sure that no square within his parcel is owned by somebody else.

读入格式

On the rst line a positive integer: the number of test cases, at most 100. After that per test case:

One line with two integers n and m (1<=n, m<=1000): the dimensions of Per’s parcel.

n lines, each with m characters. Each character is either ‘#’ or ‘.’. The j-th character on the i -th line is a ‘#’ if position (i, j) is a swamp, and ‘.’ if it is grass. The north-west corner of Per’s parcel has coordinates (1, 1), and the south-east corner has coordinates (n, m).

输出格式

Per test case:

Zero or more lines containing a complete list of how many parcels of each perimeter Per needs to
sell in order to maximize his pro t. More speci cally, if Per should sell pi parcels of perimeter i in the optimal solution, output a single line ‘pi xi ‘. The lines should be sorted in increasing order of i . No two lines should have the same value of i, and you should not output lines with pi = 0.

样例读入

1
6 5
..#.#
.#…
#..##
…#.
#….
#..#.

样例输出

6 x 4
5 x 6
5 x 8
3 x 10
1 x 12

贪心 扫描法,单调栈

题目大意:输入一个n*m(1<=n,m<=1000)的矩阵,每个格子可能是空地,也可能是沼泽。对于每个空地,求出以它为右下角的矩形最大周长,然后统计每个周长出现了所少次。如样例,“#”为沼泽,“.”为空地,答案是6*4(表示周长为4的矩形有6个)、5*6、5*8、3*10、1*2。

我们从上到下,从左到右处理每一个空地。当处理(i,j)这一空格时,由于我们是从左往右处理的,我们已经得到了一个对计算此格子有用的空地台阶(因为像台阶)。这个台阶双重有序(纵坐标是1~j-1递增的,高度由于只保留有用的,也是递增的),用一个栈记录左上角可能出现的位置,记为(c(列数),h(高度)),我们在计算这一格子时,已经知道了它向上能延伸多高(可以知道),因此从栈头弹出高度太高的,把当前列的信息放入栈中。设当前列为j,矩形周长=2*(c-j+1+h),发现周长只与c-h有关,这有利于计算最大周长。可以再O(1)时间内求出这个矩形的最大周长。

细节见代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=1010;
int n,m,top,T;
char s[N][N];
int hei[N],ans[N<<1];

struct Rect{
    int c,h;
    Rect (int c=0,int h=0):c(c),h(h){}
}sta[N];

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; ++i) scanf("%s",s[i]);
        memset(hei,0,sizeof(hei));
        memset(ans,0,sizeof(ans));
        for(int i=0, j; i<n; ++i){
            top=-1; // 清空栈  
            for(j=0; j<m; ++j){
                if(s[i][j]=='#'){
                    top=-1; // 若是沼泽,清空栈  
                    hei[j] = 0;
                }else{
                    hei[j]++;
                    Rect r(j,hei[j]);
                    if(top<0) sta[++top] = r;
                    else{
                        // 弹出太高的  
                        while(top>=0 && sta[top].h>=r.h) r.c=sta[top--].c;
                        // 如果加进去可能成为最优解,就加进去  
                        if(top<0 || sta[top].h-sta[top].c<r.h-r.c) sta[++top]=r;
                    }
                    ans[ sta[top].h+j-sta[top].c+1 ] ++;
                }
            }
        }
        for(int i=1; i<=m+n; ++i){
            if(ans[i]) printf("%d x %d\n",ans[i],i*2);
        }
    }
    return 0;
}

据说用 DP 可以不用排除所有“不可能最优”的矩形,但我不会(我是蒻蒟)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值