• 【dp】淘宝的推荐系统


    可能最近做二分和DFS做傻了?

    小明刚刚入职淘宝,老大给他交代了一个简单的任务,实现一个简易的商品推荐系统。

    这个商品推荐系统的需求如下:

    一共有 n 件商品可以被推荐,他们的编号分别为 1 到 n。每件商品都有一个价格,编号为 i 的商品价格为 pi​ 元。现在需要给用户推荐尽可能多的商品,但是要保证按照编号上升的顺序给用户依次推荐商品,并且,相邻商品的价格之差的绝对值不能超过 d。注意,第一个推荐的商品价格没有限制。

    输入格式

    第一行输入一个整数 T,表示测试数据组数。

    接下来依次输入 T 组数据,每组数据按照下面的格式输入:

    第一行输入两个整数 n 和 d,意义如题目描述所示。

    接下来一行输入 n 个整数,第 i 个整数表示 pi​。

    保证 $1<T≤50$, $1≤n≤30000$, $0≤d≤100$, $1≤pi​≤10^5$。

    保证 $∑n≤6∗10^5$。

    输出格式

    对于每组数据,输出一行一个整数,表示最多能推荐的商品个数。


    题目分析

    诶,思路大概被最近做的题目带的有点偏……

    看到的第一眼是二分,然后果断叉掉了……

    然后就开始想带记忆化的DFS,不过捣鼓了半天发现是会TLE的……

    赛时dp一直没怎么理解,直到赛后才意识到好水好水的dp题目啊……

    大概是dp姿势不太好吧……

    这个是带记忆化的DFS:

     1 #include<bits/stdc++.h>
     2 const int maxn = 50003;
     3 
     4 int tt,n,m,ans;
     5 int a[maxn],anss[maxn];
     6 bool vis[maxn];
     7 
     8 int dfs(int now)
     9 {
    10     if (vis[now]) return anss[now];
    11     int tt = now, cnt = 0;
    12     for (;;)
    13     {
    14         tt++;
    15         while (abs(a[tt]-a[now])>m) tt++;
    16         if (tt <= n) cnt = std::max(dfs(tt), cnt);
    17         else break;
    18     }
    19     vis[now] = 1;
    20     return anss[now]=cnt+1;
    21 }
    22 int main()
    23 {
    24     scanf("%d",&tt);
    25     while (tt--)
    26     {
    27         ans = 1;
    28         scanf("%d%d",&n,&m);
    29         memset(vis, 0, sizeof vis);
    30         memset(anss, 0, sizeof anss);
    31         for (int i=1; i<=n; i++) scanf("%d",&a[i]),anss[i] = 1;
    32         for (int i=1; i<=n; i++)
    33             if (!vis[i])
    34                 ans = std::max(ans, dfs(i));
    35         printf("%d
    ",ans);
    36     }
    37     return 0;
    38 }

    这个是dp:

     1 #include<bits/stdc++.h>
     2 const int maxn = 100003;
     3 
     4 int tt,x,n,m,ans;
     5 int f[maxn];
     6 
     7 int main()
     8 {
     9     scanf("%d",&tt);
    10     while (tt--)
    11     {
    12         ans = 0;
    13         scanf("%d%d",&n,&m);
    14         memset(f, 0, sizeof f);
    15         for (int i=1; i<=n; i++)
    16         {
    17             scanf("%d",&x);
    18             int w = f[x]+1;
    19             for (int j=std::max(1, x-m); j<=std::min(maxn-1, x+m); j++)   //不要局限于数据形式,把dp对象转移成权值
    20                 f[j] = std::max(f[j], w);
    21         }
    22         for (int i=1; i<maxn; i++)
    23             ans = std::max(ans, f[i]);
    24         printf("%d
    ",ans);
    25     }
    26     return 0;
    27 }

    其中注意到权值较小,我们用$f[j]$表示权值等于$j$时的最大答案值,最后再扫一遍就好了。

    关键在于这里的输入天然有序,因此$f[j]$表示$1~i-1$之中权值为$j$的答案数,也就是说这里是把n维的dp优化到了1维

    END

  • 相关阅读:
    用户反馈
    Alpha版本测试报告
    Alpha Scrum7
    #Alpha Scrum6
    Alpha Scrum5
    #Alpha Scrum4
    Alpha Scrum3
    Alpha Scrum2
    课程总结
    实验九
  • 原文地址:https://www.cnblogs.com/antiquality/p/9033693.html
Copyright © 2020-2023  润新知