【NOIP2016提高组模拟】积木

时间:2021-04-08 19:10:17

Description

【NOIP2016提高组模拟】积木

Data Constraint

【NOIP2016提高组模拟】积木

Solution

比赛的时候用了个神奇的小暴力,本来打算拿40分,没想到暴力出奇迹,随机数据下表现优良,居然碾过去了。暴力方法不讲,只贴代码,仅供对拍。
正解显然要用状态压缩(看数据范围),设 fS,i,0/1/2 ,S表示当前已选择的积木集合,i表示在最上方的积木编号,0/1/2表示最上方的积木哪面朝上。转移方程容易推导。

Code

暴力

var
    a:array[0..15,0..3] of longint;
    fx:array[1..3,1..2] of longint=((1,2),(2,3),(1,3));
    g:array[1..3] of longint=(3,1,2);
    p:array[1..15] of boolean;
    n,i,j,k,ans:longint;
function max(x,y:longint):longint;
begin
    if x>y then exit(x) else exit(y);
end;
procedure dfs(x,high,l,r:longint);
var i,j:longint;
begin
    if x=0 then exit;
    for i:=1 to n do
        if p[i]=false then
        begin
            p[i]:=true;
            for j:=1 to 3 do
            if (l>=a[i,fx[j,1]])and(r>=a[i,fx[j,2]]) then
            begin
                ans:=max(ans,high+a[i,g[j]]);
                dfs(x-1,high+a[i,g[j]],a[i,fx[j,1]],a[i,fx[j,2]]);
            end;
            p[i]:=false;
        end;
end;
begin
    readln(n);
    for i:=1 to n do
    begin
        for j:=1 to 3 do read(a[i,j]);
        readln;
        for j:=1 to 2 do
            for k:=j+1 to 3 do
            if a[i,j]>a[i,k] then
            begin
                a[i,0]:=a[i,j];a[i,j]:=a[i,k];a[i,k]:=a[i,0];
            end;
    end;
    dfs(n,0,maxlongint,maxlongint);
    writeln(ans);
end.

正解

var
    s,i,j,k,jj,n,x,y,xx,yy,z,temp,ans:longint;
    a:array[1..15,1..3] of longint;
    f:array[0..100000,1..15,1..3] of longint;
    mi:array[0..15] of longint;
procedure max(var x:longint;y:longint);
begin
    if y>x then x:=y;
end;
procedure fu(i,j:longint;var x,y:longint);
begin
    case j of
        1:begin x:=a[i,2]; y:=a[i,3]; end;
        2:begin x:=a[i,1]; y:=a[i,3]; end;
        3:begin x:=a[i,1]; y:=a[i,2]; end;
    end;
end;
procedure swap(var x,y,z:longint);
begin
    if x<y then
    begin temp:=x;x:=y;y:=temp; end;
    if x<z then
    begin temp:=x;x:=z;z:=temp; end;
    if y<z then
    begin temp:=y;y:=z;z:=temp; end;
end;
begin
    read(n);
    mi[0]:=1; for i:=1 to n do mi[i]:=mi[i-1]*2;
    for i:=1 to n do
    begin
        read(x,y,z); swap(x,y,z);
        a[i,1]:=x; a[i,2]:=y; a[i,3]:=z;
    end;
    for i:=1 to n do
    begin f[mi[i-1],i,1]:=a[i,1]; f[mi[i-1],i,2]:=a[i,2];
    f[mi[i-1],i,3]:=a[i,3]; end;
    for s:=1 to mi[n]-1 do
        for i:=1 to n do
            for j:=1 to 3 do if f[s,i,j]>0 then
            begin
                max(ans,f[s,i,j]);
                fu(i,j,x,y);
                for k:=1 to n do if mi[k-1] and s=0 then
                    for jj:=1 to 3 do
                    begin
                        fu(k,jj,xx,yy);
                        if (x>=xx) and (y>=yy) then
                        max(f[s+mi[k-1],k,jj],f[s,i,j]+a[k,jj])
                    end;
            end;
    writeln(ans);
end.