zoukankan      html  css  js  c++  java
  • Codeforces K. Shaass and Bookshelf(动态规划三元组贪心)

    题目描述:

    B. Shaass and Bookshe
    time limit per test    2 seconds
    memory limit per test 256 megabytes
    input   standard input
    output  standard output

    Shaass has n books. He wants to make a bookshelf for all his books. He wants the bookshelf's dimensions to be as small as possible. The thickness of thei-th book isti and its pages' width is equal towi. The thickness of each book is either1 or2. All books have the same page heights.

    Shaass puts the books on the bookshelf in the following way. First he selects some of the books and put them vertically. Then he puts the rest of the books horizontally above the vertical books. The sum of the widths of the horizontal books must be no more than the total thickness of the vertical books. A sample arrangement of the books is depicted in the figure.

    Help Shaass to find the minimum total thickness of the vertical books that we can achieve.
    Input

    The first line of the input contains an integer n,(1 ≤ n ≤ 100). Each of the nextn lines contains two integersti andwi denoting the thickness and width of thei-th book correspondingly, (1 ≤ ti ≤ 2, 1 ≤ wi ≤ 100).
    Output

    On the only line of the output print the minimum total thickness of the vertical books that we can achieve.
    Sample test(s)
    Input

    5
    1 12
    1 3
    2 15
    2 5
    2 1

    Output

    5

    Input

    3
    1 10
    2 1
    2 4

    Output

    3

    思路:

    题目是要把书要么横着放,要么竖着放,要求在横着放的宽度不大于竖着放的宽度下的数着宽度的最小值。

    刚开始:既然是DP,我就设状态,dp[i][j]表示放前i本书,横着放的宽度不大于j的情况下的,竖着宽度的最小值。

    状态出来了,那我就转移吧。dp[i][j] = dp[i-1][j]+v[i](表示第i本书我竖着放),dp[i][j] = min(dp[i][j],dp[i][j]-w[i])(表示第i本书我横着放)。

    但是,有问题,这样做求不出正确答案,因为不一低满足上面的数的长度小于等于下面的书的长度,最后就算在dp[n][i]中找满足条件的,但在dp数组计算过程中就可能已经把正确答案消掉了。(如果有dalao是类似于这种定义dp做出来的,请不吝赐教,欢迎留言)

    然后:改一种定义方法:dp[i][j]表示当前放低i本书,竖着放的长度是j的情况下,横着放的长度的最小值,转移方程是,dp[i][j] = dp[i-1][j]+w[i](我横着放),dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]])(我竖着放)

    最后在dp[n][i]里找满足条件的最小i,就是解

    代码:

     1 #include <iostream>
     2 #include <memory.h>
     3 #define max_n 105
     4 #define INF 0x3f3f3f3f
     5 using namespace std;
     6 int w[max_n];
     7 int v[max_n];
     8 int dp[max_n][max_n*2];
     9 int n;
    10 int C = 0;
    11 int main()
    12 {
    13     cin >> n;
    14     for(int i = 1;i<=n;i++)
    15     {
    16         cin >> v[i] >> w[i];
    17         C+=v[i];
    18     }
    19     memset(dp,0x3f,sizeof(dp));
    20     dp[0][0] = 0;
    21     /*for(int i = 0;i<=n;i++)
    22     {
    23         for(int j = 0;j<=C;j++)
    24         {
    25             cout << dp[i][j] << " ";
    26         }
    27         cout << endl;
    28     }*/
    29     int tot = 0;
    30     for(int i = 1;i<=n;i++)
    31     {
    32         tot+=v[i];
    33         for(int j = 0;j<=tot;j++)
    34         {
    35             dp[i][j] = dp[i-1][j]+w[i];
    36             if(j>=v[i]) dp[i][j] = min(dp[i][j],dp[i-1][j-v[i]]);
    37         }
    38     }
    39     /*for(int i = 0;i<=n;i++)
    40     {
    41         for(int j = 0;j<=C;j++)
    42         {
    43             cout << dp[i][j] << " ";
    44         }
    45         cout << endl;
    46     }*/
    47     int minm = INF;
    48     for(int i = 0;i<=C;i++)
    49     {
    50         if(i>=dp[n][i])
    51         {
    52            cout << i << endl;
    53            break;
    54         }
    55     }
    56     return 0;
    57 }

    还有一种做法,好理解,但内存占用比较大,定义三元组dp[i][j][k],(还好数据小),表示放第i本书后竖着摆长度为j横着摆长度k的状态是否存在,是为1,不是为0

    转移方程是在三重循环下,if(j>=v[j]&&dp[i-1][j-v[i]][k]) dp[i][j][k] = 1;if(k>w[i]&&dp[i][j][k-w[i]) dp[i][j][k] = 1;

    最后遍历一遍找最小的满足dp[n][j][k]的j

    代码:

     1 #include <iostream>
     2 #include <memory.h>
     3 #define max_n 105
     4 #define INF 0x3f3f3f3f
     5 using namespace std;
     6 int w[max_n];
     7 int v[max_n];
     8 int dp[max_n][max_n*2][max_n*2];
     9 int n;
    10 int C = 0;
    11 int main()
    12 {
    13     cin >> n;
    14     for(int i = 1;i<=n;i++)
    15     {
    16         cin >> v[i] >> w[i];
    17         C+=v[i];
    18     }
    19     dp[0][0][0] = 1;
    20     for(int i = 1;i<=n;i++)
    21     {
    22         for(int j = 0;j<=C;j++)
    23         {
    24             for(int k = 0;k<=200;k++)
    25             {
    26                 if(j>=v[i]&&dp[i-1][j-v[i]][k])
    27                 {
    28                     dp[i][j][k] = 1;
    29                 }
    30                 if(k>=w[i]&&dp[i-1][j][k-w[i]])
    31                 {
    32                     dp[i][j][k] = 1;
    33                 }
    34             }
    35         }
    36     }
    37     int flag = 1;
    38     for(int j = 0;j<=C&&flag;j++)
    39     {
    40         for(int k = 0;k<=j&&flag;k++)
    41         {
    42             if(dp[n][j][k])
    43             {
    44                 cout << j << endl;
    45                 flag = 0;
    46             }
    47         }
    48     }
    49     return 0;
    50 }

    最后,听说可以用贪心来枚举做哦,试一试。因为书的厚度只有两种,1或2,那么将书分类,在每一类中以书的宽度降序排序,最后要使竖着放的宽度最小,就把每类书的前i,j本书竖着放(因为宽度相对大)二重循环枚举出所有i,j,求满足条件的最小值。编码5分钟,调bug两小时,,,结果发现错在了cmp函数上,合着sort的cmp和qsort的还不一样啊,还有就是求和数组的下标让我疯狂。((╯‵□′)╯︵┻━┻)

    代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #define max_n 105
     4 #define INF 0x3f3f3f3f
     5 using namespace std;
     6 int n;
     7 struct book
     8 {
     9     int v;
    10     int w;
    11 };
    12 book bk1[max_n];
    13 book bk2[max_n];
    14 int cnt1 = 0;
    15 int cnt2  =0;
    16 int sum1[max_n];//记录前i本1类书宽度和
    17 int sum2[max_n];//记录前i本2类书宽度和
    18 int cmp(book a,book b)
    19 {
    20     return a.w>b.w;
    21 }
    22 int main()
    23 {
    24     cin >> n;
    25     int v,w;
    26     for(int i = 0;i<n;i++)
    27     {
    28         cin >> v >> w;
    29         if(v==1)
    30         {
    31             bk1[cnt1].v = v;
    32             bk1[cnt1].w = w;
    33             cnt1++;
    34         }
    35         if(v==2)
    36         {
    37             bk2[cnt2].v = v;
    38             bk2[cnt2].w = w;
    39             cnt2++;
    40         }
    41     }
    42     //cout << cnt1 << " " << cnt2 << endl;
    43     sort(bk1,bk1+cnt1,cmp);
    44     sort(bk2,bk2+cnt2,cmp);
    45     /*for(int i = 0;i<cnt2;i++)
    46     {
    47         cout << bk2[i].w << " " << endl;
    48     }*/
    49     sum1[0] = 0;
    50     sum1[1] = bk1[0].w;
    51     for(int i = 2;i<=cnt1;i++)
    52     {
    53         sum1[i] = sum1[i-1]+bk1[i-1].w;
    54     }
    55     sum2[0] = 0;
    56     sum2[1] = bk2[0].w;
    57     for(int i = 2;i<=cnt2;i++)
    58     {
    59         sum2[i] = sum2[i-1]+bk2[i-1].w;
    60     }
    61     //cout << sum1[cnt1] << " and " << sum2[cnt2] << endl;
    62     int sum = 0;
    63     int ans = INF;
    64     for(int i = 0;i<=cnt1;i++)
    65     {
    66         for(int j = 0;j<=cnt2;j++)
    67         {
    68             sum = i+2*j;
    69             w = sum1[cnt1]-sum1[i]+sum2[cnt2]-sum2[j];
    70             //cout << "i " << i << " j " << j << " sum " << sum << " w " << w << endl;
    71             if(w<=sum&&sum<ans)
    72             {
    73                 ans = sum;
    74             }
    75         }
    76     }
    77     cout << ans << endl;
    78     return 0;
    79 }
  • 相关阅读:
    思考未来:你的目标是什么
    从非同凡响开始:绝不要做他人也在做的事
    Elasticsearch的内置分词器
    Elasticsearch倒排索引的核心组成
    Session 与 JWT
    vue全屏组件
    css弹性盒骰子
    es6模块化
    移动端适配
    echarts-3D地图
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11233557.html
Copyright © 2011-2022 走看看