zoukankan      html  css  js  c++  java
  • dp乱写2:论dp在不在dp中(但在dp范畴)内的应用

    最近正儿八经的学习了dp,有一些题目非常明显看出来就是dp了
    比如说:过河卒、方格取数、导弹拦截、加分二叉树、炮兵阵地
    更加明显的还有:采药、装箱问题、过河、金明的预算方案。
    今天来谈谈dp的dp在不在dp中(但在dp范畴)内的应用(简称dp的应用)
    dp其实可以用贪心来优化,有些基本不可能的情况就可以直接省略了。
    dp其实可以用数据结构来优化,取最大值最小值用堆。。。
    dp其实不一定是dp,也可以是一种思想,的简称dp思想,
    就是用前面的一个或者两个状态来推出现在状态的可能,解决一些问题有神效。
    dp的空间基本上是n^2或者m^2(用滚存也是少数啊3转2其实也可以滚的啊)
    如果看到n=1,000;m=1,000的数据范围就想到dp啦。
    但是问题来了,不是每一题符合从前推到后且n,m比较小的题目就是dp。
    但是用dp思想一定没错啦。。。
    下面有个小例子来阐述一下p在不在dp中(但在dp范畴)内的应用(简称dp的应用)
    【题目名称】游览(sightseeing.pas/c/cpp)
    【题目描述】周末到了,gnocuil打算去逛游乐园。他所去的游乐园可以看做一个N*M的网格,每个网格上都是一个景点。游乐园的入口在(1,1),出口在(N,M)处。游乐园有一个不成文的规定:游览时,只能朝着坐标增大的方向走,因为如果坐标减小,会很不吉利。换句话说,每次只能向右方、正下方走。当然,只可以走到相邻的景点,不可以沿着斜线走。
    对于走到的每个景点,gnocuil都会得到一个快乐度A[i,j]。同时,游览会使他疲倦,每个景点都会使他增加B[i,j]的疲劳度。
    gnocuil认为,对于每次游览,用总快乐度除以总疲劳度,得到的就是这次游览的价值。请你设计一个方案,使得对于给定的游乐园信息,游览的价值最大。
    【输入文件】第一行是两个整数N,M,表示游乐园的大小。
    接下来N行每行M个正整数,表示这个景点的快乐度。
    接下来N行每行M个正整数,表示这个经典的疲劳度。
    【输出文件】只有一个实数,表示最大价值。精确到小数点后5位小数。
    【输入样例】

    2 2
    1 2
    1 1
    1 1
    2 1

    【输出样例】

    1.33333

    【样例说明】只有两条线路:(1,1)->(1,2)->(2,2)的价值是(1+2+1)/(1+1+1)=1.33333,(1,1)->(2,1)->(2,2)的价值是(1+1+1)/(1+2+1)=0.75000。
    【图】自己画啦。
    现在我要阐述的是这题怎么用dp(思想)来解题。
    首先,直接DP显然错误,因为(A1+A2)/(B1+B2)不可能被分解成A1/B1和A2/B2的形式。
    一个反例见测试点2:
    input#2

    5 5
    3 5 4 4 4
    4 3 4 4 4
    4 3 3 3 4
    5 5 3 5 5
    3 5 5 4 5
    1 1 1 1 2
    2 1 2 2 2
    1 1 2 1 1
    2 2 2 1 2
    2 1 1 2 1

    output#2

    3.45454

    这不是一个luo的坐标dp,如果不能dp,那还玩个毛线?(放弃)
    其实我们仔细分析还是可以用dp的思路给出解答。
    本题求的是:max(∑Ai/∑Bj)。设max (∑Ai/∑Bj)=k,即对于最优解, ∑Ai=k∑Bj
    也就是Max k,k满足 ∑(Ai-kBj)=0;
    换句话说,因为Ai和Bj是给定的,只要对于某个答案k,得到上式=0,就可以断定k是合法的答案。在此基础上求出最大的合法的k。
    怎样确定答案k?
    枚举!只需二分k,再进行判断即可。
    二分k的过程中,如果k偏小,就会有 max(∑Ai/∑Bj)>k,也就是∑(Ai-kBj)>0 反之亦然。
    也就是说我们每次二分答案的时候还是需要用到坐标dp的(套路深~~)
    假设f[i,j]表示∑(Ai-kBj)的最大值(走到(i,j)时得到的价值的最大值)

     for i:=1 to n do
      for j:=1 to m do
       f[i,j]:=max(f[i-1,j],f[i,j-1])+a[i,j]-k*b[i,j];

    这个状态转移真心不难啊!!!
    然后就可以愉快的二分了。(注意double二分格式,最后输出l)

    var n,m,i,j:longint;
        f:array[0..1000,0..1000]of double;
        a,b:array[1..1000,1..1000]of longint;
        l,r,mid:double;
    function max(a,b:double):double;
    begin
     if a>b then exit(a)
     else exit(b);
    end;
    function pd(k:double):boolean;
    var i,j:longint;
    begin
     for i:=1 to n do
      for j:=1 to m do
       f[i,j]:=max(f[i-1,j],f[i,j-1])+a[i,j]-k*b[i,j];
     exit(f[n,m]>0);
    end;
    begin
    assign(input,'sightseeing.in');
    assign(output,'sightseeing.out');
    reset(input);
    rewrite(output);
     readln(n,m);
     for i:=1 to n do
      for j:=1 to m do
       read(a[i,j]);
     for i:=1 to n do
      for j:=1 to m do
       read(b[i,j]);
     for i:=1 to n do f[i,0]:=-1e300;
     for j:=1 to m do f[0,j]:=-1e300;
     f[0,1]:=0;
     l:=0; r:=1000;
     while r-l>1e-6 do begin
      mid:=(l+r)/2;
      if pd(mid)then l:=mid
                else r:=mid;
     end;
     writeln(l:0:5);
     close(input);
     close(output);
    end.
  • 相关阅读:
    dockor 在windows的安装步骤
    go gin框架安装流程
    go 引入包之后没有起作用
    go get github.com/gin-gonic/gin 下载失败
    group 与having使用例子
    php把服务器上的资源下载并保存本地
    mysql 自我连接表
    laravel 队列的简单例子
    rem和em,px的使用
    带进度条的自动跳转页面代码
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/7367840.html
Copyright © 2011-2022 走看看