uva12265 selling land

来源:互联网 发布:淘宝试用报告模板 编辑:程序博客网 时间:2024/05/05 18:13

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. Figure 1: In this example, dark squares represent swamp. Per
may, for example, sell three overlapping grey areas, with dimensions 2
 1, 2  4 and 4  1 respectively. The total perimeter is 6 + 12 + 10
= 28. Note that he can get more money by selling even more land. This gure corresponds to the case in the sample input. 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. Input 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 ). Output 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 p i parcels of perimeter i in the
optimal solution, output a single line ` p i x i ‘. 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 p i
= 0.

逐行进行扫描。
先预处理出每一列草地的高度height[j]【可以由上一行的值O(m)推得】。在从左往右扫描的过程中,维护可能为最优解的矩形左上端点。记横坐标为c,高度为h。则栈【随后解释为什么用栈】中的元素,c递增,h也递增。需要对于当前位置c0,找到最优解,也就是2(c0-c+1+h)最大。不难看出,要让h-c最大。而随着向右扫描,一些c比较大的元素的h有可能变小甚至被删除【因为h需要不断和当前高度取min,而且如果连续两个元素被取min的话,右边的元素没有必要保留(因为他们的h相同了)】,导致其h-c缩水,而且需要注意的是c大的一定比c小的元素先变小【因为c大的h也一定大,否则不会留在单调栈里】。因此我们不能只保留一个当前h-c的最大值。但是,如果c1小于c2且h1-c1大于h2-c2的话,不但2比1先缩水,而且缩水前的值都不如1好。因此2没有必要保留。所以最后维护的单调序列,应该是一个c递增、h递增、h-c也递增的序列。由于插入和删除都是对c最大【最靠右】的元素进行,所以可以采用单调栈。而h-c递增,所以对于当前扫描到的位置,栈顶元素就是它的最优解。
对于一行从左往右扫描,维护某一位置信息时,先根据当前高度进行栈顶的修改和删除,然后(如果可以)插入该位置作为元素,最后得出该位置的解。
时间复杂度O(mn)。
虽然说起来很麻烦,但是代码并不长。

#include<cstdio>#include<cstring>#define M(a) memset(a,0,sizeof(a))struct pos{    int c,h;}sta[1010];int map[1010][1010],height[1010],ans[2020];int main(){    int i,j,k,l,m,n,p,q,x,y,z,T,tot,cnt,top;    char s[1010];    scanf("%d",&T);    while (T--)    {        M(sta);        M(map);        M(height);        M(ans);        scanf("%d%d",&n,&m);        for (i=1;i<=n;i++)        {            scanf("%s",s+1);            for (j=1;j<=m;j++)              map[i][j]=(s[j]=='.')?1:0;        }        for (i=1;i<=n;i++)        {            for (j=1;j<=m;j++)              if (map[i][j]) height[j]++;              else height[j]=0;            top=0;            for (j=1;j<=m;j++)              if (height[j])              {                if (top==0)                {                    ans[1+height[j]]++;                    top++;                    sta[top].c=j;                    sta[top].h=height[j];                    continue;                }                while (top>=2&&sta[top-1].h>=height[j]) top--;                if (sta[top].h>height[j]) sta[top].h=height[j];                if (top>=2&&sta[top].h-sta[top].c<=sta[top-1].h-sta[top-1].c) top--;                if (height[j]-j>sta[top].h-sta[top].c)                {                    top++;                    sta[top].c=j;                    sta[top].h=height[j];                }                ans[j-sta[top].c+sta[top].h+1]++;              }              else top=0;        }        for (i=1;i<=m+n;i++)          if (ans[i])            printf("%d x %d\n",ans[i],i*2);    }}
0 0
原创粉丝点击