zoukankan      html  css  js  c++  java
  • 动态规划初步

    终于开了动态规划的坑,经过一番挣扎算是会了最基本的东西。详细的讲解到处都有,这里想说的是我的一点理解...

    有这样一类问题:问题有多步决策;后面的决策不影响前面的决策。比如01背包:

    有四个物品:(重量,价值)为(2,4),(3,5),(4,8),(1,3),在总重不超过4的情况下怎么拿价值最大。

    为什么不能贪心?

    我先想到的解法是按性价比大小排序,先拿性价比高的直到拿不动,但是显然:拿(1,3)和(2,4)不是最优。因为有别的组合能更充分利用剩余空间

    为什么要用动态规划?

    其实对于每个物品,要么拿,要么不拿,有两种决策,如果用回溯法,显然时间复杂度(2^n),有点大。而动态规划的时间复杂度O(mn)或者说O(n^2),显然是个巨大的优化。

    虽然表面上动态规划算了很多没用的问题,实际上那些都是最终问题的子问题,而且想优化下空间可以用滚动数组。

    怎么理解状态转移方程d【i,j】=max(d(i+1,j),d(i+1, j-weight【i】)+value【i】)?

    在老滚五里捡破烂,你捡到了金矿,又遇到了银矿,拿不动不拿;遇到了龙骨,把金矿丢了拿龙骨。其实就是这样(误)。

    我手动填了一下引例中的d【i,j】表格:不要在意光线和ps痕迹

    为什么要倒着推?

    这个就要说到规划方向。d(i,j)可以定义为:只考虑前i个物品,剩余空间为j时的最大价值。但是还有一种规划方向:后i个物品,剩余空间为j,这两种方向有微妙的差别。

    如果想打印路径,要从终点出发向起点找,如果使用方向1,d【起点,空间】是想要的最大价值,这时找路径会倒序进行,如果要求找字典序最小的路径,比较难处理。

    而使用方向2,d【1,空间】是答案,找路径是从前往后进行,比较方便在多个路径之间比较出最优的路径(比如有字典序的奇怪要求)。

    怎么找出路径?(可能有多个路径)

    这个事其实挺困惑的,网上我没找到好的答案,自己最后还是用了dfs(但是这个不会耗太多时间,因为他只是找出答案路径),效果不错,而且可以一边找路径一边归纳最优路径。

    具体实现的话,最后放一个oj1175:world final2

    Problem Description

    The World Final is coming! Next week our seniors, Brother Head, Little Bin and God Tan will fight for the glory of NEU.

    The rule of the world final is as follow:

    1. if two teams have the different solved problems, then the one who have more solved problems will get higher rank;

    2. if two teams have the same solved problems, then the one who have less penalty, which equals 0 initially, will get higher rank;

    3. if one team get first AC of a problem, then their penalty will add a number which equal the time they first AC it, and if they tried failed k times to solve it before they AC it, then they will get more k*20 penalty;

    4. the total time of the world final is 300 (including 300), and begin at time 0.

    Now our seniors know how long will they solve each problem and how many times will they failed before they AC it. They wanna take a best strategy to get higher rank.

    Input

    There are T groups of test data. The first line contains one positive integer T (1<=T<=100). 

    For each test data : the first line contains an integer n(1<=n<=15), which is the number of total problems. Then follows n line, each line contains two numbers: ti and ki,(1<=ti<=300, 0<=ki<=1000) which means how long will they AC it (not the time they AC it), and how many times they failed before they AC it.

    【hint】:

    In the second sample input, they solve the 2nd problem firstly, then solve the 1st problem, solve they solved 2 problems in total, and penalty=(2+100*20)+(292+2*20)=2334.

    Output

    For each case, output one line contains two numbers separated by a space: the most number of problems they can solve, and the less penalty in that case.

     
    Sample Input
    2 2 290 2 299 1 3 290 2 2 100 299 1
    Sample Output
    1 319 2 2334
    Source
    morejarphone
    Hint
    No Hint!

    world final上有n道题,时间300min,给出做每道题的用时和罚时,在做出最多题的情况下想让罚时总时间最少。总时间等于每道题ac的时长加罚时,问过题数和总时间。

    其实就是01背包中每个物品价值为1,找出最大价值后,在各个方案之间比较,选出最好。

    如果使用方向2,那么是正向打印路径,正好从小到大排序每道题用时即可(做的题固定,先做用时少的题更好) 然后是最难受的环节

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int sp = 300;
    struct test
    {
        int w, v;
    }T[20];
    int cmp(test a, test b)
    {
        return a.w < b.w;
    }
    int d[20][310];
    int n, minsum;
    int main()
    {
        void dfs(int cur, int left, int world, int sum);
        int t;
        scanf("%d", &t);
        while(t--)
        {
            scanf("%d", &n);
            for(int i = 1; i <= n; i++)
            {
                scanf("%d%d", &T[i].w, &T[i].v);
                T[i].v *= 20;
            }
            sort(T+1, T+n+1, cmp);
            //不需要memset d数组,想想为什么
            for(int i = 0; i <= sp; i++)
                d[n+1][i] = 0;
            for(int i = n; i >= 1; i--)
                for(int j = 0; j <= sp; j++)
                {
                    d[i][j] = d[i+1][j];
                    if(j >= T[i].w)
                        {
                            d[i][j] = max(d[i][j], d[i+1][j-T[i].w]+1);
                        }
                }
            minsum = 1e9;
            dfs(1, sp, 0, 0);
            printf("%d ", d[1][sp]);
            printf("%d
    ", minsum);
        }
        return 0;
    }
    void dfs(int cur, int left, int world, int sum)//cur是物品层数,left剩余空间,world当前用时,sum总用时
    {
        if(cur == n+1)
        {
            if(sum < minsum)
                minsum = sum;
            return;
        }
        int i = cur, j = left;
        if(j >= T[i].w && d[i][j] == d[i+1][j-T[i].w]+1)
            dfs(cur+1, left-T[i].w, world+T[i].w, sum+world+T[i].w+T[i].v);
        if(d[i][j] == d[i+1][j])
            dfs(cur+1, left, world, sum);
    }

     上战果:,香港记者的速度。

    最后膜拜world final学长 太强了

    搞图论是没有用的,转行做数学题了hh
  • 相关阅读:
    Android 5.X新特性之RecyclerView基本解析及无限复用
    Android 网络框架之Retrofit2使用详解及从源码中解析原理
    Android 源码解析之AsyncTask
    Business Logic
    WHO AM I
    黑洞
    俄罗斯方块
    还记得八皇后的解法吗
    汝之蜜糖,吾之砒霜
    项目为什么会失败
  • 原文地址:https://www.cnblogs.com/DearDongchen/p/6979700.html
Copyright © 2011-2022 走看看