解题报告 Toy Bricks

Toy Bricks

【题目描述】

Ray又在NPC问题了:这里有一个箱子,还有若干个玩具。 

我们可以假设玩具的数量是没有上限的。我们还知道这个箱子是不规则的,或者可以说,他的外形比较像一个矩形,但是内部却有很多突起,这些突起很可恶,他可以一直突到玩具的顶盖部。为了简化这个NPC问题,Ray只保留了一种形状的玩具

    ○

○  ○  ○

    ○

Ray想知道对于一个给定的箱子,最多可以放下多少个这样的玩具。

【输入格式】

第一行两个用空格隔开的整数n 和 m 表示玩具想的长度和宽度

第二行到第n+1行,每行m个用空格隔开的字符‘#’’.‘;’#’表示这里是一个障碍物。’.’表示这里可以放东西。

【输出格式】

一行一个整数表示最多的玩具个数

【输入样例】

5 4

#.#.

…#

#..#

#...

##.#

【输出样例】

2

【数据范围】

0<=n<=100

0<=m<=10

 

 

状态压缩动规,参见炮兵阵地。

 

program lonely;

 

  const

    maxn=maxlongint shr 1;

 

  var

    tot,jj,kk,l,zz,ttttt,ss,i,j,n,m,k,t,temp,ans:longint;

    b,sum:array[0..2000] of integer;

    z:array[0..2000] of integer;

    g:array[0..2000,0..2000] of integer;

    f:array[0..1,0..2000,0..2000] of longint;

    c:char;

 

  begin

    assign(input,'toy.in');

    reset(input);

    assign(output,'toy.out');

    rewrite(output);

 

    readln(n,m);

    fillchar(sum,sizeof(sum),0);

 

    for i:=0 to 1 shl m-1 do

      begin

        t:=i;

        while t>0 do

          begin

            inc(sum[i]);

            t:=t-(t and (-t));

          end;

      end;   //最多能放多少个

 

    fillchar(z,sizeof(z),0);

    for i:=1 to n do

      begin

        for j:=0 to m-1 do

          begin

            read(c);

            if c='#' then

              z[i]:=z[i]+1 shl j;

          end;

        readln;

      end;   //设置障碍

 

    tot:=0;

    fillchar(g,sizeof(g),0);

    fillchar(b,sizeof(b),0);

    for i:=0 to 1 shl m-1 do

      begin

        if (i and 1=1)or(i shl 1>(1 shl m-1)) then continue;

        if (i shl 1)and i<>0 then continue;

        if (i shl 2)and i<>0 then continue;   //不能放置

        inc(tot);

        b[tot]:=i;

        g[i,0]:=0;

        for j:=0 to 1 shl m-1 do

          begin

            if (j and 1=1)or(j shl 1>(1 shl m-1)) then continue;

            if (i and j<>0) then continue;

            if (j shl 1)and j<>0 then continue;

            if (j shl 2)and j<>0 then continue;

            if (i shl 1)and j<>0 then continue;

            if (j shl 1)and i<>0 then continue;   

            inc(g[i,0]);

            g[i,g[i,0]]:=j;

          end;

      end;

 

    for i:=0 to 1 do

      for j:=0 to 1025 do

        for k:=0 to 1025 do

          f[i,j,k]:=-maxn;

    f[1,0,0]:=0;

    t:=0;

    for i:=2 to n-1 do

      begin

        for jj:=1 to tot do

          for kk:=1 to tot do

            begin

              j:=b[jj];k:=b[kk];

              if f[1-t,j,k]>=0 then

                begin

                  for l:=1 to g[j,0] do

                    begin

                      temp:=g[j,l];

                      if temp and z[i]<>0 then continue;

                      if (temp shr 1)and(z[i])<>0 then continue;

                      if (temp shl 1)and(z[i])<>0 then continue;

                      if temp and z[i+1]<>0 then continue;

                      if temp and z[i-1]<>0 then continue;

                      if temp and k<>0 then continue;

                      ss:=sum[temp];

                      if f[1-t,j,k]+ss>f[t,temp,j] then

                        f[t,temp,j]:=f[1-t,j,k]+ss;

                    end;

                  f[1-t,j,k]:=-maxn;

                end;

            end;

        t:=1-t;

      end;    //状态压缩动规。

 

    ans:=0;

    for i:=1 to tot do

      for j:=1 to tot do

        if f[1-t,b[i],b[j]]>ans then

          ans:=f[1-t,b[i],b[j]];     //统计

    writeln(ans);

 

    close(input);

    close(output);

  End.

 

 

 

 

补充,解题报告  炮兵阵地

 

1. 题目  炮兵阵地

    还是宇宙时间公元5.5亿年,maxingc联盟用微子来攻击yun联盟。愤怒的yun联盟决定反戈一击,他们准备使用加农炮来反击。

yun联盟的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由NM列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 

 


如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

第一行包含两个由空格分割开的正整数,分别表示NM 
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100M <= 10

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4

PHPP

PPHH

PPPP

PHPP

PHHP

Sample Output

6

2. 题目实质

数据变态一点的,改了改要求的 皇后,不过是要求求 

3. 题目来源  怎么又是集训?

4. 算法

虽然他跟 皇后怎么看怎么类似,但是从那该死的数据范围(N <= 100M <= 10)。可以看出,用单纯的搜肯定过不了。

由于m<=10,所以每一行的状态可以用二进制表示,放置炮兵记为1,不放置记为0每一行的状态只和前两行的状态有关系,所以有方程: F[i,k1,k2]=Max{f[i-1,k2,k3]+num[k1]},其中i为行数,k1表示第i行的状态,k2表示第i-1行的状态,k3表示第i-2行的状态,num[k1]k1状态下可放置炮兵的个数。    i,k1k2k3必须满足一定的关系(炮兵之间不能相互攻击,且炮兵不能放在山地上)。    对于状态a[k1]a[k2],如果他们是可行的,讨论他们每个对应的位置。    a[k1]如果某位置是1,a[k2]这位上必须是0    a[k1]如果某位置是0,a[k2]这位上可以是1,也可以是0    所以可以归纳出  a[k1] and a[k2]=0,这要判断矛盾可以使速度大大提高。

用这种 and 的方法可以应付很多变态的判断。    对于每一行,第i种状态能不能放上去,即要求不能在‘H’的地方放士兵。    我们可以先把每行原来的初始状态也表示出来,但是这里有个小技巧,把‘H’的地方记录下来。    这行如果某位置是1,那么在a[k1]中这个位置上必须为01代表这里是山地)。    这行如果某位置是0,那么在a[k1]中这个位置上可以为1,可以为00代表这里是平原)。    所以可以归纳出  now[i] and a[k1]=0now数组表示地形的状态)。

当然,这种题,一般,大概,也许,都是第四题,所以拿裸宽搜偏偏分也没什么不好,不然这么变态的程序,想要在考试的时候敲出来真的是有点……

5. 注意事项

注意看数据范围,这玩意跟 皇后还真有点不一样。

这里的二进制优化也就是 HASH 优化,所以注意这关键的 HASH 函数要写对!

其实这个款搜有点动态规划的意思,但这个动态规划中的状态是要用款搜进行预处理的,千万别忘了。

还有这个判断矛盾的方法可以学一下。

6. 时空复杂度  On^2

7. 程序代码

Pascal

var f:array[0..100,0..100,0..100] of longint;

now,b,a:array[0..100] of longint; ch:char;

i,j,n,m,sum,t,tt,ans,k1,k2,k3:longint; s:string;

 function deal(x:longint):string;

  var s:string; k:longint;

   begin

    k:=x; s:='';

while k>0 do

 begin

  s:=chr(k mod 2+48)+s;

  k:=k div 2;

 end;

  exit(s);

end;

 begin

  assign(input,'cannon.in'); reset(input);

  assign(output,'cannon.out'); rewrite(output);

  readln(n,m);

  for i:=1 to n do

   begin

    for j:=1 to m do

     begin

      read(ch);

      if ch='H' then now[i]:=now[i]+1 shl (m-j);

    end;

      readln;

   end;

      for i:=0 to (1 shl m)-1 do

       begin

         s:=deal(i);

         for j:=1 to m-length(s) do s:='0'+s;

         tt:=0; t:=0;

         for j:=1 to m do

          if s[j]='1' then

           begin

            if (s[j+1]='1') and (j+1<=m) then t:=1;

            if (s[j+2]='1') and (j+2<=m) then t:=1;

            if t=1 then break;

            inc(tt);

           end;

            if t=0 then

             begin

              inc(sum);

              a[sum]:=i;

              b[sum]:=tt;

             end;

       end;

             for i:=1 to sum do

              f[1,i,1]:=b[i];

             for i:=2 to n do

              for k1:=1 to sum do

               for k2:=1 to sum do

                if (a[k1] and a[k2]=0) and

(a[k1] and now[i]=0) and (a[k2] and now[i-1]=0) then

  for k3:=1 to sum do

           if (a[k2] and a[k3]=0) and (a[k3] and now[i-2]=0)

                   and (a[k1] and a[k3]=0) then

            if f[i,k1,k2]<f[i-1,k2,k3]+b[k1] then

             f[i,k1,k2]:=f[i-1,k2,k3]+b[k1];

      for i:=1 to sum do

       for j:=1 to sum do

                       if (a[i] and a[j]=0) and (a[i] and now[n]=0)

                       and (a[j] and now[n-1]=0) then

        if f[n,i,j]>ans then ans:=f[n,i,j];

writeln(ans);

close(input);

close(output);

 end.

    

 

 

转载于:https://www.cnblogs.com/SueMiller/archive/2011/10/27/2226771.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值