• [二分][状压dp] Jzoj P3521 道路覆盖


    Description

    ar把一段凹凸不平的路分成了高度不同的N段,并用H[i]表示第i段高度。现在Tar一共有n种泥土可用,它们都能覆盖给定的连续的k个部分。

    对于第i种泥土,它的价格为C[i],可以使得区间[i,min(n,i+k-1)] 的路段的高度增加E[i]。

    Tar要设定一种泥土使用计划,使得使用若干泥土后,这条路最低的高度尽量高,并且这个计划必须满足以下两点要求:

    (1)每种泥土只能使用一次。

    (2)泥土使用成本必须小于等于M。

    请求出这个最低的高度最高是多少。
     

    Input

    第一行为如上文所示的三个正整数:N,M,K。

    接下来N行,每行3个如上文所示的正整数H[i],E[i],C[i]。

    Output

    输出有且只有一个数字,为最底部分的高度的最大值
     

    Sample Input

    4 20 1
    1 3 5
    1 7 3
    4 6 9
    3 5 13

    Sample Output

    3
     

    Data Constraint

    对于30%的数据:N≤20。

    对于100%的数据:1≤K≤11,1≤N≤100,0≤M,H[i],E[i],C[i]≤1000000。

    题解

    • 最小值最大,显然二分
    • 现在二分出来一个最低高度,思考一下怎么判断
    • 考虑dp,设f[i][s]为当前到第i位前k个位用泥土的状态为s(是否有用)
    • 那么就很显然了,每次转移前现算出前k个给当前位的贡献,设为num
    • 转移就有两种一种是当前位不选,一种是当前位选
    • 状态转移方程就很显然了
    • ①f[i+1][j>>1]=min(f[i+1][j>>1],f[i][j]);
      ②f[i+1][(j>>1)|(1<<(k-1))]=min(f[i+1][(j>>1)|(1<<(k-1))],f[i][j]+c[i+1]);

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 int n,m,k,sum,mx,num,h[110],e[110],c[110],f[110][1<<12];
     6 bool check(int x)
     7 {
     8     memset(f,127,sizeof(f)),f[0][0]=0;
     9     for (int i=0;i<=n-1;i++)
    10         for (int j=0;j<=(1<<k)-1;j++)
    11         {
    12             num=0;
    13             for (int z=1;z<=k-1;z++) if (j&(1<<z)) num+=e[i-k+z+1];
    14             if (num+h[i+1]>=x) f[i+1][j>>1]=min(f[i+1][j>>1],f[i][j]);
    15             if (num+h[i+1]+e[i+1]>=x) f[i+1][(j>>1)|(1<<(k-1))]=min(f[i+1][(j>>1)|(1<<(k-1))],f[i][j]+c[i+1]);
    16         }
    17     for (int i=0;i<=(1<<k)-1;i++) if (f[n][i]<=m) return true;
    18     return false;
    19 }
    20 int main()
    21 {
    22     freopen("cover.in","r",stdin),freopen("cover.out","w",stdout);
    23     scanf("%d%d%d",&n,&m,&k);
    24     for (int i=1;i<=n;i++) scanf("%d%d%d",&h[i],&e[i],&c[i]),sum+=e[i],mx=max(mx,h[i]);
    25     int l=1,r=sum+mx;
    26     while (l<r)
    27     {
    28         int mid=(l+r)>>1;
    29         if (check(mid)) l=mid+1; else r=mid;
    30     }
    31     printf("%d",l-1);
    32 }    
  • 相关阅读:
    还贷的那些事V——等增幅还贷的计算
    计算机中的颜色X——两颜色的偏转值
    高亮显示不区分大小写的关键字——ASP
    一道算法题,看看大家的思路
    一道算法题,看看大家的思路(续)
    IQCar的实现II——解题思路
    IQCar的实现I——IQCar的介绍
    Flex画流程图
    jQuery源码研究01
    javascript笔记:javascript里面不同function定义的区别
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9826406.html
Copyright © 2020-2023  润新知