【NOIP2016提高组模拟】积木

20 篇文章 0 订阅

Description

这里写图片描述

Data Constraint

这里写图片描述

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.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值