【LUOGU P1220】关路灯(区间dp)
一開始直接搜索+剪枝,拿了50分,發現原來是搜索搜復雜了..因為搜索是可以過的
注意到題目中有一句''再回過頭來關掉另一邊的路燈,而事實并非如此,因為在關的過程中適當地調頭有可能會更省一些",也就是說老王是在沿著某個方向走著走著突然轉向,而不是毫無邏輯的,我之前寫的搜索枚舉就是毫無邏輯的
for(int i=1;i<=n;i++){if(vis[i]) continue;vis[i]=true;dfs(...);vis[i]=false;}而應該策略是:對于每個位置,去尋找左邊沒關掉的燈或者右邊沒有關掉的燈。之后dfs ,尋找最優情況
不過話說回來,這道題本質上是一個很好的區間DP
我們發現老王關過的燈是屬于一個區間的,而不是跳著跳著的關,因此設dp[i][j]表示老王已關閉區間[i,j]的燈,但是老王既可以在左邊也可以在右邊,所以再加一維[0/1]表示老王在左還是右
則有方程:
f[i][j][0] = min ( f[i+1][j][0] + ( a[i+1] - a[i] ) * ( sum[i] + sum[n] - sum[j] ) , f[i+1][j][1] + ( a[j]-a[i] ) * ( sum[i]+sum[n]-sum[j]) );
f[i][j][1] = min ( f[i][j-1][0] + ( a[j] - a[i] ) * ( sum[i-1] + sum[n] - sum[j-1] ) , f[i][j-1][1] + ( a[j]-a[j-1] ) * ( sum[i-1] + sum[n] - sum[j-1] ) );
其中sum是前綴和,要注意的是每次乘上的總功耗是包含了當前點i(j)的
#include<bits/stdc++.h> #define N 55 using namespace std; int n,c; int dp[N][N][2],dis[N],w[N],sum[N]; int main() {cin>>n>>c;for(int i=1;i<=n;i++){cin>>dis[i]>>w[i];sum[i]=sum[i-1]+w[i];}memset(dp,63,sizeof(dp));dp[c][c][0]=0,dp[c][c][1]=0;for(int len=2;len<=n;len++){for(int st=1;st+len-1<=n;st++){int ed=st+len-1;dp[st][ed][0]=min(dp[st+1][ed][0]+(sum[n]-sum[ed]+sum[st])*(dis[st+1]-dis[st]),dp[st+1][ed][1]+(sum[n]-sum[ed]+sum[st])*(dis[ed]-dis[st]));dp[st][ed][1]=min(dp[st][ed-1][1]+(sum[n]-sum[ed-1]+sum[st-1])*(dis[ed]-dis[ed-1]),dp[st][ed-1][0]+(sum[n]-sum[ed-1]+sum[st-1])*(dis[ed]-dis[st]));}}cout<<min(dp[1][n][0],dp[1][n][1])<<endl;return 0; }轉載于:https://www.cnblogs.com/Patrickpwq/articles/9825484.html
總結
以上是生活随笔為你收集整理的【LUOGU P1220】关路灯(区间dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 笔记本usb驱动识别不了怎么办 笔记本U
- 下一篇: zabbix 安装使用