Tar 把一段凹凸不平的路分成了高度不同的 N 段(每一段相同高度),并用 H[i] 表示第 i 段高度。现在 Tar 一共有 n 种泥土可用,它们都能覆盖给定的连续的 k 个部分。
对于第 i 种泥土,它的价格为 C[i],可以使得区间 [i,min(n,i+k-1)] 的路段的高度增加 E[i]。
Tar 要设定一种泥土使用计划,使得使用若干泥土后,这条路最低的高度尽量高,并且这个计划必须满足以下两点要求:
(1)每种泥土只能使用一次。
(2)泥土使用成本必须小于等于 M 。
请求出这个最低的高度最高是多少。
刷题总结——道路覆盖(ssoj)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题总结——道路覆盖(ssoj)相关的知识,希望对你有一定的参考价值。
题目:
题目描述
输入格式
第一行为如上文所示的三个正整数:N,M,K。
接下来 N 行,每行3个如上文所示的正整数 H[i],E[i],C[i]。
输出格式
输出有且只有一个数字,为最底部分的高度的最大值。
样例数据 1
备注
【数据范围】
对于 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)的主要内容,如果未能解决你的问题,请参考以下文章