• NOIP提高组2016 D2T3 【愤怒的小鸟】


    貌似还没有写过状压DP的题目,嗯,刚好今天考了,就拿出来写一写吧。

    题目大意:

    额,比较懒,这次就不写了。。。

    思路分析:

    先教大家一种判断题目是不是状压DP的方法吧。

    很简单,那就是——看数据范围!一般状压DP的题目,数据都会在10到20左右。

    那么有了状压的思路以后,这题应该怎么来做呢?

    很容易想到的是:枚举任意两个点,算出抛物线的解析式,然后预处理出n2条抛物线每条抛物线经过猪的集合(假设存在line[i,j]中),预处理就是这样了。状压DP的话就是,二进制第i位的0/1表示第i只猪是否被打死,f[sta]就表示现在猪的状态为sta时,最小的拉弹弓次数。对于每一种状态,n2枚举新加的抛物线经过的两个端点,那么f[sta|line[i,j]]=min(f[sta|line[i,j]],f[sta]+1)。

    时间复杂度是n2*2n的,考场上是85分,洛谷上能过。

    正解其实只是在原先的基础上加了一个小小的优化。

    对于一种sta状态,假设:1,2,3,4这四头猪未被打,1,2在同一条抛物线上,3,4在另一条抛物线上。那么先打1,2再打3,4的效果和先打3,4再打1,2的效果是一样的。所以我们就指定在这一次拉弹弓时一定要打到x号猪,这样就能够优化掉一个n变成n*2n

    代码实现:

    var
      f,lowunbit:array[0..500000]of longint;
      x,y:array[0..20]of double;
      line:array[0..20,0..20]of longint;
      i,j,k,n,m,sta,t,oo:longint;
      a,b,jd:double;
    function min(a,b:longint):longint;
    begin
      if a<b then exit(a) else exit(b);
    end;
    procedure equation(a1,a2,b1,b2,y1,y2:double);
    begin
      a:=(y1-y2*b1/b2)/(a1-b1*b2);
      b:=(y1-a1*a)/b1;
    end;
    begin
      for i:=0 to 1<<18-1 do
        for j:=0 to 18 do
          if i>>j and 1=0 then
            begin lowunbit[i]:=j+1; break; end;
      read(t);
      jd:=0.000001;
      while t>0 do
      begin
        fillchar(f,sizeof(f),$7f);
        fillchar(line,sizeof(line),0); 
        oo:=f[0];
        read(n,m);
        for i:=1 to n do
          read(x[i],y[i]);
        for i:=1 to n do
          for j:=1 to n do
            if x[i]<>x[j] then
            begin
              equation(x[i]*x[i],x[j]*x[j],x[i],x[j],y[i],y[j]);
              if a>-jd then continue;
              for k:=1 to n do
                if abs(x[k]*x[k]*a+x[k]*b-y[k])<jd then
                  line[i,j]:=line[i,j]or 1<<(k-1);
            end;
        f[0]:=0;
        for sta:=0 to 1<<n-2 do
          if f[sta]<>oo then
          begin
            i:=lowunbit[sta];
            f[sta or 1<<(i-1)]:=min(f[sta or 1<<(i-1)],f[sta]+1);
            for j:=1 to n do
              f[(sta)or(line[i,j])]:=min(f[(sta)or(line[i,j])],f[sta]+1);
          end;
        writeln(f[1<<n-1]);
        dec(t);
      end;
    end.
  • 相关阅读:
    文件上传按钮样式定制
    消除2个按钮之间1px细节引起的冲突
    css 实用代码汇总
    除掉inline-block 间距
    SQL Server 创建索引的 5 种方法
    百度API从经纬度坐标到地址的转换服务
    百度地图API简单应用——1.根据地址查询经纬度
    极光API推送 (v3 版本)
    简单快捷地测试 JPush API
    使用极光推送(www.jpush.cn)向安卓手机推送消息【服务端向客户端主送推送】C#语言
  • 原文地址:https://www.cnblogs.com/WR-Eternity/p/9844446.html
Copyright © 2020-2023  润新知