围巾裁剪

围巾裁剪

 

   裁缝有一块非常珍贵的丝绸围巾。可惜的是,围巾的某些部分已经被蛀虫给咬坏了。裁缝当然不愿意就这么把围巾给丢了,于是,他想把围巾给裁成两块小围巾送给他的两个女儿。自然,两块小围巾的面积之和越大越好。

这块围巾是一个正三角形,三条边被均匀地分成了N段,即这个正三角形被均匀地分成了N2个单元,每个单元是一个面积为1的正三角形。图一所示为一个N=5的围巾,图中带阴影的单元表示被蛀虫咬坏的部分。从上往下看,围巾被分成了N行,第一行有1个单元,第二行有3个单元,其中有2个是形如D 的,有1个是形如Ñ 的(这两种三角形我们认为是形状相同的)。第三行有5个,其中有3个是形如D 的,有2个是形如Ñ 的…… 。用坐标(X,Y)给每个单元定位,第一行的单元的坐标为(1,1);第二行从左到右的三个单元的坐标依次为(2,1)、(2,2)、(2,3);…。

 

 

 

围巾的剪裁条件如下:

1. 裁成的两块小围巾形状与原来的大围巾完全相同,都是正三角形。 

2. 每一块小围巾里都不存在被蛀虫咬坏的部分。 

3. 裁剪时必须沿着单元的边界裁剪。 

4. 要求两块小围巾的面积的总和最大。 

图一中,最优的裁剪方法已经用粗线画了出来,面积和为4+9=13。

现在需要你编一个程序来帮助裁缝解决这个问题。

输入

输入文件第一行为一个整数N(1£ N£ 100,表示这块围巾总共被分成了N2个单元。第二行为一个整数M(0£ M£ N2-2),表示这块围巾共有M个单元被蛀虫咬坏了。接下的M行,每一行有两个正整数X和Y,为这M个被蛀虫咬坏的单元的坐标。

输入文件中同一行相邻两项之间用一个或多个空格隔开。

 

输出

输出文件仅含一个整数,为你所找到的裁出两块小围巾面积总和的最大值。

 

样例输入

5

5

3 2

4 1

4 4

5 4

5 2

 

样例输出

13

 解题思路

    乍一看,这简直就是一道绝世难题【对本菜来说】,当时连卡出翔的想法都有了。再一看,哇哈哈哈,我顿时大笑,仁义有如关云长,但是就是关云长也做不出此题,所以我也不会。经过一番精密的推断验算之后,我确定了如下方法:

    【1】,利用递推思想,分别求出在每一个【小三角形】中,以该【小三角形】为【最顶部三角形】的【最大三角形】的层数。

    【2】,依次枚举分割线,将整个三角形分成一个小三角形与一个梯形,再在每一个小图形中求出最大三角形的层数,再更新答案的值。

    【3】,每次枚举完之后,将三角形顺时针旋转120度【本质就是考虑斜着切割的情况】,再重复步骤1和2.

    【4】,将步骤3循环3次。

参考程序pascal

var
    i,j,k,l,m,n,x,y,t,max:longint;
    a,b:array[1..100,1..200]of longint;

function min(x,y:longint):longint;
begin
    if x<y then exit(x) else exit(y);
end;

procedure each;//求出以每一个小三角形为顶点的最大三角形层数
var
    i,j:longint;
begin
    for i:=1 to n do
    begin
        if a[n,i*2-1]<>-1 then
        begin
            a[n,i*2-1]:=1;
        end;
    end;


    for i:=n-1 downto 1 do
    begin
        for j:=1 to i do
        begin
            if a[i,j*2-1]<>-1 then
            begin
                a[i,j*2-1]:=1;
                if (a[i+1,j*2-1]<>-1)and(a[i+1,j*2]<>-1)and(a[i+1,j*2+1]<>-1) then
                begin
                    a[i,j*2-1]:=min(a[i+1,j*2-1],a[i+1,j*2+1])+1;
                end;
            end;
        end;
    end;

    for i:=2 to n do
    begin
        for j:=1 to i-1 do
        begin
            if a[i,j*2]<>-1 then
            begin
                a[i,j*2]:=1;
                if (j>1) and (j<i-1) and (a[i-1,(j-1)*2]<>-1) and (a[i-1,(j-1)*2+1]<>-1) and(a[i-1,j*2]<>-1) then
                begin
                    a[i,j*2]:=min(a[i-1,(j-1)*2],a[i-1,j*2])+1;
                end;
            end;
        end;
    end;
end;

procedure search;//枚举分割线,查找在分割线内的最大三角形
var
    i,j,k,max1,max2:longint;
begin

    for i:=1 to n-1 do
    begin
        max1:=0;
        max2:=0;
        for j:=1 to i do
        begin
            for k:=1 to j do
            begin
                if min(i-j+1,a[j,k*2-1])>max1 then max1:=min(i-j+1,a[j,k*2-1]);
            end;
            for k:=1 to j-1 do
            begin
                if a[j,k*2]>max1 then max1:=a[j,k*2];
            end;
        end;
        for j:=i+1 to n do
        begin
            for k:=1 to j do
            begin
                if a[j,k*2-1]>max2 then max2:=a[j,k*2-1];
            end;
            for k:=1 to j-1 do
            begin
                if min(j-i,a[j,k*2])>max2 then max2:=min(j-i,a[j,k*2]);
            end;
        end;
        if (max1<>0)and(max2<>0)and(max1*max1+max2*max2>max) then
        begin
            max:=max1*max1+max2*max2;
        end;
    end;

end;

procedure turn;//将三角形旋转
var
    i,j,k:longint;
begin
    for i:=1 to n do
    begin
        for j:=1 to i do
        begin
            if a[i,j*2-1]=-1 then
            begin
                b[n-i+j,(n-i)*2+1]:=-1;
            end;
        end;
        for j:=1 to i-1 do
        begin
            if a[i,j*2]=-1 then
            begin
                b[n-i+j+1,(n-i+1)*2]:=-1;
            end;
        end;
    end;
end;

begin
    assign(input,'cut.in'); reset(input);
    assign(output,'cut.out'); rewrite(output);
    readln(n);
    readln(m);
    for i:=1 to m do
    begin
        readln(x,y);
        a[x,y]:=-1;
    end;

    for t:=1 to 3 do
    begin

        each;
        search;
        fillchar(b,sizeof(b),0);
        turn;
        for i:=1 to n do
            for j:=1 to 2*i-1 do
            begin
                a[i,j]:=b[i,j];
            end;
    end;
    writeln(max);
    close(input);
    close(output);
end.

 

posted on 2013-10-14 22:11  H2H BIT 1  阅读(797)  评论(0)    收藏  举报

导航