比较典的区间dp
P1220 关路灯
很典的一道题,但是以前居然不知道。
数据范围很小,可以直接搜索通过,加一些奇奇怪怪的贪心策略和剪枝即可和正解差不多速度通过。
ll ans=9e18; int n,st,loc[51],p[51]; void dfs(int x,ll t,ll res,ll P,int l,int r){ res+=t*p[x]; P-=p[x]; if(res+P*t>=ans)return; if(!l&&r==n+1)return ans=res,void(); if(l)dfs(l,t+loc[x]-loc[l],res,P,l-1,r); if(r<=n)dfs(r,t+loc[r]-loc[x],res,P,l,r+1); } int main(){ n=read(),st=read(); ll P=0; for(int i=1;i<=n;i++) loc[i]=read(),P+=p[i]=read(); dfs(st,0,0,P,st-1,st+1); cout<<ans<<endl; return 0; }
然后基于上述搜索用到的贪心:每次只可能向左或向右拓展一格,证明显然。
所以不难推出转移,因为要记在左边还是右边,所以我们开三维
int n,st,loc[52]; ll sum[52],f[2][52][52];//0 is left inline ll cal(int l,int r){return sum[l-1]+sum[n]-sum[r];} int main(){ n=read(),st=read(); for(int i=1;i<=n;i++) loc[i]=read(),sum[i]=sum[i-1]+read(); memset(f,0x3f,sizeof(f)); f[0][st][st]=f[1][st][st]=0; for(int len=2;len<=n;len++) for(int i=1;i+len-1<=n;i++){ int j=i+len-1; f[0][i][j]=min(f[0][i+1][j]+cal(i+1,j)*(loc[i+1]-loc[i]),f[1][i+1][j]+cal(i+1,j)*(loc[j]-loc[i])); f[1][i][j]=min(f[0][i][j-1]+cal(i,j-1)*(loc[j]-loc[i]),f[1][i][j-1]+cal(i,j-1)*(loc[j]-loc[j-1])); } printf("%lld",min(f[0][1][n],f[1][1][n])); return 0; }
P2466 [SDOI2008] Sue 的小球
和上面那道的贪心思路差不多,都是左右扩展是最优的,所以转移方程差不多,要注意的是,这个需要类似于离散化的方式重构数组,然后就和上面那题一样了。不过注意如果像我这样直接整数保留三位要先输出负号,否则会被除法吞掉。
const int N=1003; int n,st,loc[N]; ll sum[N],ans,f[2][N][N]; map<int,int>M; inline ll cal(int l,int r){return sum[l-1]+sum[n]-sum[r];} int main(){ n=read(),M[st=read()]=0; for(int i=1;i<=n;i++)loc[i]=read(); for(int i=1;i<=n;i++)ans+=read(); for(int i=1;i<=n;i++)M[loc[i]]+=read(); int be=n=0; for(auto PI:M){ loc[++n]=PI.first; if(PI.first==st)be=n; sum[n]=sum[n-1]+PI.second; } memset(f,0x3f,sizeof(f)); f[0][be][be]=f[1][be][be]=0; for(int len=2;len<=n;len++) for(int i=1;i+len-1<=n;i++){ int j=i+len-1; f[0][i][j]=min(f[0][i][j],min(f[0][i+1][j]+cal(i+1,j)*(loc[i+1]-loc[i]),f[1][i+1][j]+cal(i+1,j)*(loc[j]-loc[i]))); f[1][i][j]=min(f[1][i][j],min(f[0][i][j-1]+cal(i,j-1)*(loc[j]-loc[i]),f[1][i][j-1]+cal(i,j-1)*(loc[j]-loc[j-1]))); } ans-=min(f[0][1][n],f[1][1][n]); if(ans<0)putchar('-'),ans=-ans; printf("%lld.%03lld",ans/1000,ans%1000); return 0; }
P4870 [BalticOI 2009 Day1] 甲虫
和 P2466 那题的 dp 思路有点相似,只不过这题因为
const int N=303; int n,m,loc[N],f[2][N][N],ans; int main(){ n=read(),m=read(); for(int i=1;i<=n;i++)loc[i]=read();loc[++n]=0; sort(loc+1,loc+1+n); int st=lower_bound(loc+1,loc+1+n,0)-loc; for(int maxl=2;maxl<=n;maxl++){ memset(f,0x3f,sizeof(f)); f[0][st][st]=f[1][st][st]=0; for(int len=2;len<=maxl;len++) for(int i=1,j=len;j<=n;i++,j++) f[0][i][j]=min(f[0][i+1][j]+(maxl-len+1)*(loc[i+1]-loc[i]),f[1][i+1][j]+(maxl-len+1)*(loc[j]-loc[i])), f[1][i][j]=min(f[0][i][j-1]+(maxl-len+1)*(loc[j]-loc[i]),f[1][i][j-1]+(maxl-len+1)*(loc[j]-loc[j-1])); for(int i=1;i<=n;i++) ans=max(ans,m*(maxl-1)-min(f[0][i][i+maxl-1],f[1][i][i+maxl-1])); } cout<<ans; return 0; }
后记
暂时不想写 dp 了,去练习图论了。
2023.11.6 16:18 end
本文作者:NBestの思潮
本文链接:https://www.cnblogs.com/NBest/p/17813010.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步