• 序列最大收益(冬季每日一题 3)


    给定一个长度为 m m m 的整数序列 a 1 , a 2 , … , a m a_1,a_2,…,a_m a1,a2,,am

    序列中每个元素的值 a i a_i ai 均满足 1 ≤ a i ≤ n 1≤a_i≤n 1ain

    当一个值为 i i i 的元素和一个值为 j j j 的元素相邻时,可以产生的收益为 w i , j w_{i,j} wi,j

    现在,我们可以从序列中删除最多 k k k 个元素,删除一些元素后,原本不相邻的元素可能会变得相邻。

    序列的收益和为所有相邻元素对产生的收益之和,例如一个长度为 3 3 3 的整数序列 1 , 3 , 2 1,3,2 1,3,2 的收益和为 w 1 , 3 + w 3 , 2 w_{1,3}+w_{3,2} w1,3+w3,2

    请问,通过利用删除操作,能够得到的序列的最大收益和是多少?

    输入格式
    第一行包含三个整数 n , k , m n,k,m n,k,m

    第二行包含 m m m 个整数 a 1 , a 2 , … , a m a_1,a_2,…,a_m a1,a2,,am

    接下来 n n n 行,每行包含 n n n 个整数,其中第 i i i 行第 j j j 列的数表示 w i , j w_{i,j} wi,j

    输出格式
    输出序列的最大收益和。

    数据范围
    对于 30% 的数据, 1 ≤ n , k , m ≤ 20 1≤n,k,m≤20 1n,k,m20
    对于 100% 的数据, 1 ≤ n , k , m ≤ 200 , 0 ≤ w i , j ≤ 1 0 7 , 1 ≤ a i ≤ n 1≤n,k,m≤200,0≤w_{i,j}≤10^7,1≤a_i≤n 1n,k,m2000wi,j1071ain
    数据保证 w i , j = w j , i , w i , i = 0 w_{i,j}=w_{j,i},w_{i,i}=0 wi,j=wj,iwi,i=0

    输入样例:

    4 1 3
    1 4 2
    0 3 0 1
    3 0 0 0
    0 0 0 0
    1 0 0 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出样例:

    3
    
    • 1

    样例解释
    初始序列收益和为 w 1 , 4 + w 4 , 2 = 1 + 0 = 1 w_{1,4}+w_{4,2}=1+0=1 w1,4+w4,2=1+0=1

    删除中间的 4 4 4 后,序列 1 , 2 1,2 1,2 的收益和为 w 1 , 2 = 3 w_{1,2}=3 w1,2=3


    思路

    状态表示 f [ i ] [ j ] f[i][j] f[i][j]

    • 集合:只考虑前 i i i个数,共删除了 j j j个数,且不删除第 i i i个数的所有方案的集合
    • 属性: m a x max max

    状态计算

    • 考虑 i i i前面的那个数
      可以将集合划分为
      i i i前面的数没有, i i i前面的数字是第 1 , 2... , x , . . . , i − 1 1,2...,x,...,i-1 1,2...,x,...,i1
      假如 i i i前面的数字是第 x x x个数字
      所以 [ x [x [x~ i ] i] i]之间就删除了 i − x − 1 i-x-1 ix1 个数
      由于此时的状态是 f [ i ] [ j ] f[i][j] f[i][j]所以 [ 1 [1 [1~ x ] x] x]之间就要删除 j − ( i − x − 1 ) j-(i-x-1) j(ix1) 个数字
      所以 f [ i ] [ j ] = f [ x ] [ j − ( i − x − 1 ) ] + w [ a [ x ] ] [ a [ i ] ] f[i][j] = f[x][j-(i-x-1)] + w[a[x]][a[i]] f[i][j]=f[x][j(ix1)]+w[a[x]][a[i]]
    #include
    #include
    
    using namespace std;
    
    const int N = 210;
    
    int n, k, m;
    int a[N], w[N][N], f[N][N];
    
    int main(){
        
        memset(f, -0x3f, sizeof f);
        scanf("%d%d%d", &n, &k, &m);
        for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                scanf("%d", &w[i][j]);
        
        f[1][0] = 0;
        for(int i = 2; i <= m; i++)
            for(int j = 0; j <= k; j++)
                for(int u = 1; u < i; u++)
                    if(j >= i - u - 1)
                        f[i][j] = max(f[i][j], f[u][j-(i-u-1)]+w[a[u]][a[i]]);
        
        int res = 0;
        for(int i = 0; i <= k; i++)
            res = max(res, f[m][i]);
        
        printf("%d\n", res);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    13.django-admin组件
    ChatGPT如何训练自己的模型
    乐趣国学—品读《弟子规》中的“泛爱众”之道(上篇)
    理解渲染,吃透渲染,你应该知道的Android渲染优化小技巧
    超详细!魔改为中文sqlmap的使用教程
    网站授权QQ登录
    深入浅出程序设计竞赛(基础篇)
    激活数据价值,探究DataOps下的数据架构及其实践丨DTVision开发治理篇
    如何 吧一个 一维数组 切分成相同等分,一维数组作为lstm的输入(三维数据)的数据预处理 collate_fn的应用
    一文详解不同路径
  • 原文地址:https://blog.csdn.net/qq_46456049/article/details/127712420