码迷,mamicode.com
首页 > 其他好文 > 详细

刷题总结——道路覆盖(ssoj)

时间:2017-07-29 19:35:38      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:style   bsp   for   false   引用   code   min   底部   size   

题目:

题目描述

Tar 把一段凹凸不平的路分成了高度不同的 N 段(每一段相同高度),并用 H[i] 表示第 i 段高度。现在 Tar 一共有 n 种泥土可用,它们都能覆盖给定的连续的 k 个部分。
对于第 i 种泥土,它的价格为 C[i],可以使得区间 [i,min(n,i+k-1)] 的路段的高度增加 E[i]。
Tar 要设定一种泥土使用计划,使得使用若干泥土后,这条路最低的高度尽量高,并且这个计划必须满足以下两点要求:
(1)每种泥土只能使用一次。
(2)泥土使用成本必须小于等于 M 。
请求出这个最低的高度最高是多少。

输入格式

第一行为如上文所示的三个正整数:N,M,K。
接下来 N 行,每行3个如上文所示的正整数 H[i],E[i],C[i]。

输出格式

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

样例数据 1

输入  [复制]

 

 

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

输出

3

备注

【数据范围】
对于 30% 的数据:N≤20。
对于 100% 的数据:1≤K≤11;1≤N≤100;0≤M,H[i],E[i],C[i]≤1000000。

题解:

引用ssoj官网题解:

二分+DP
二分答案ans,问题转化为了判定性问题。判定的方法是:每个位置都能到达高度ans的最小费用cost是否<=M。
注意到1<=K<=11,也就是说对于第i个路段,能够提高它高度的泥土只有从第i-K个到第i个。于是使用状态压缩动态规划求cost。f[i][j]表示前i个路段通过泥土使用>=高度ans,且第i - k个到第i个的使用情况为二进制数j

注意位运算打括号!!!!!!!

注意dp初始化!!!!!


代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=105;
const int inf=1e+9;
int n,m,k;
int h[N],e[N],c[N];
int bit[15];
int dp[N][5000],g[5000];
bool jud[N];
inline int R()
{
  int f=0;
  char c;
  for(c=getchar();(c<0||c>9);c=getchar());
  for(;c<=9&&c>=0;c=getchar())
    f=(f<<3)+(f<<1)+c-0;
  return f;
}
inline int find(int x)
{
  for(int i=k-1;i>=0;i--)
    if(x>=bit[i])  return i;
}
inline bool work(int minn)
{
  memset(dp,-1,sizeof(dp));
  dp[0][0]=0;
  memset(jud,false,sizeof(jud));
  jud[0]=true;
  for(int i=1;i<=n;i++)
  {
    if(!jud[i-1])  
      return false;
    g[0]=0;
    int maxx=(i<k?bit[i]:bit[k]);
    for(int j=0;j<maxx;j++)
    {
      int temp;
      if(j==0)  g[j]=0;
      else
      {  
        temp=find(j);
        g[j]=g[j-bit[temp]]+e[i-temp];
      }
      if(g[j]+h[i]<minn)  continue; 
      if(dp[i-1][j>>1]==-1&&dp[i-1][(j>>1)+bit[k-1]]==-1)  continue;
      if(dp[i-1][j>>1]==-1)  
        temp=dp[i-1][(j>>1)+bit[k-1]];
      else
      {  
        if(dp[i-1][(j>>1)+bit[k-1]]==-1)
          temp=dp[i-1][j>>1];
        else
          temp=min(dp[i-1][j>>1],dp[i-1][(j>>1)+bit[k-1]]);  
      }
      dp[i][j]=temp+(j&1)*c[i];
      if(dp[i][j]>m)  dp[i][j]=-1;
      else jud[i]=true;
    }
  }
  return jud[n];
}
int main()
{
 // freopen("a.in","r",stdin);
  n=R(),m=R(),k=R();
  for(int i=1;i<=n;i++)
    h[i]=R(),e[i]=R(),c[i]=R();
  bit[0]=1;
  for(int i=1;i<=k;i++)
    bit[i]=bit[i-1]*2;
  int left=inf,right;
  for(int i=1;i<=n;i++)
    left=min(left,h[i]);
  right=h[1]+e[1];
  for(int i=1;i<=n;i++)
  {
    int temp=h[i];
    for(int j=i;j>=i-k+1&&j>=1;j--)
      temp+=e[j];
    right=max(temp,right);
  }
  int ans=left;
  while(left<=right)
  {
    int mid=(left+right)/2;
    if(work(mid))  ans=mid,left=mid+1;
    else  right=mid-1;
  }
  cout<<ans<<endl;
  return 0;
}

 

刷题总结——道路覆盖(ssoj)

标签:style   bsp   for   false   引用   code   min   底部   size   

原文地址:http://www.cnblogs.com/AseanA/p/7257158.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!