zoukankan      html  css  js  c++  java
  • 机器分配----线性dp难题(对于我来说)

    题目:

    总公司拥有高效设备M台, 准备分给下属的N个分公司。各分公司若获得这些设备,可以为国家提供一定的盈利。问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值。其中M <= 15,N <= 10。分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数M。

    (非常简洁的题面,没有之一)

    输入:

    第1行有两个数,第一个数是分公司数N,第二个数是设备台数M。接下来是一个N*M的矩阵,表明了第i个公司分配j台机器的盈利。

    输出:

    第1行输出最大盈利值。接下来N行,每行2个数,即分公司编号和该分公司获得设备台数。

    样例:

    3 3         70

    30 40 50 ===>            1 1

    20 30 50                     2 1

    20 25 30      3 1

    题面也很好理解:找出最大的分配方式,并输出路径。

    思路:

    1.求最大值,思路是线性dp,第 i 行 j 列的结果只与这一行选几个,和他上面的行选几个有关,所以可以用dp的思路来解。转移方程是

    dp[ i ][ j ]=max(dp [ i ][ j ],dp[ i - 1 ][ k ]+a[ i ][ j - k ] );

    2.保存路径

     这一步是比较难的,对代码能力的要求较高,也是这道题的考点,先上一个比较暴力的,但肯定对的:

     

    void Print(int i,int j){
    	if(i==0)return;
    	for(int k=0;k<=j;k++){
    		if(Max==dp[i-1][k]+a[i][j-k]){
    			Max=dp[i-1][k];
    			Print(i-1,k);
    			printf("%d %d
    ",i,j-k);
    			break;
    		}
    	}
    }
    

     递归输出,在主函数里Print(n,m)。这样写相当于每一行都重新算了一遍。

    (ps:这道题题目要求本来是输出N行,每行包括第 i 家公司和他所选的台数,但是这样递归输出,如果有的公司一台没选,这样的公司是不会输出的)

    错误样例:2 2      666

         1 666======》 1 2

         1 1

    (但是这道题的数据太菜了,这样写也能a。。。)

    第二种方法:一般的用res数组保存每排每列所选的k,然后输出(我改这个改了11次也没过,哭辽!)

    (不要抄这个!不要抄这个!不要抄这个!这个会WA!!!)

    就讲一下思路吧。。。

    if(dp[i][j]<=dp[i-1][k]+a[i][j-k]){
         dp[i][j]=dp[i-1][k]+a[i][j-k];
              M[i][j]=k;
    }
    if(Max<=dp[i][j]){
         Max=dp[i][j];
            F1=i;F2=j;
    }

     M[ i ][ j ]保存dp[ i ][ j ]的决策中选的那个k,F i,F j保存最大结果的  i, j 。

    因为要从1~N输出,所以需要递归保存一下:

    void Print(int i,int j){
        if(M[i][j]==0){
            ans[i]=j-M[i][j];
            return;
        }
        Print(i-1,M[i][j]);
        ans[i]=j-M[i][j];
    }

    ans[ i ]保存第 i 个公司所选机器数量。

    然后输出结果即可。

    这道题为什么这样写会WA呢?

    附上错误样例:

    2 15

    1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

    1 1 1 1 1 1 1 1 1 1 1 1 1 1 2

    大家自己思考一下,这样该怎么输出路径?

    显然 1 1     1 0

        2 1     2 15

    的结果都是一样的,MAX=2。

    标准答案和这个代码的结果各据其一。

    就是一个多解没spj压正解的题。。。

    总结:这道题主要难点有两个,一是转移方程,二是输出路径。

    然后就没了。。。

     

  • 相关阅读:
    Codeforces Round#410 Div.2
    AtCoder Beginner Contest-060
    如何将gedit变成c++编译器
    洛谷 P2486 [SDOI2011]染色
    让lu哥头痛了许久的代码(洛谷:树的统计)
    字符串模拟入门
    luogu P1553 数字反转(升级版)
    那些令人难忘的——坑
    luogu P1341 无序字母对
    最短路相关题目
  • 原文地址:https://www.cnblogs.com/liu-yi-tong/p/13178905.html
Copyright © 2011-2022 走看看