P1220 关路灯 (有点不同的区间dp)

P1220 关路灯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

本题有个很重要的信息:大爷是可以随手关灯,所以对于区间[i~j],出于贪心,大爷最后要么在 i 位置,要么在 j 位置。

令DP[i][j][0/1],为0时在 i 位置,为1时在 j 位置 关掉区间[ i , j ]所需的最少时间(这跟P3205 [HNOI2010]合唱队的dp状态很像) 

考虑区间dp[i][j][0/1]的转移:

先考虑dp[i][j][0]。;

如果我们考虑 k 便是考虑 dp[i][k][0/1]与dp[k+1][j][0/1],但这也™的难写,而且在走的过程中,dp[i][k][0/1]与dp[k+1][j][0/1]直接好像没法联系一起,因为走的时候还要考虑其他亮着的灯消耗的功率。

但实际上dp[i][j][0]只会从dp[i+1][j][0/1]转移过来

对于dp[i+1][j][0]:dp[i][j][0]=dp[i+1][j][0]+(pos[i+1]-pos[i])*(sum[n]-(sum[j]-sum[i])).(从pos[i+1]走到pos[i],其他的灯还是亮着会消耗,这一段很容易忘写)

对于dp[i+1][j][1]:dp[i][j][0]=dp[i+1][j][1]+(pos[j]-pos[i])*(sum[n]-(sum[j]-sum[i])).

所以:dp[i][j][0]=min(dp[i+1][j][0]+(pos[i+1]-pos[i])*(sum[n]-(sum[j]-sum[i])),

          dp[i+1][j][1]+(pos[j]-pos[i])*(sum[n]-(sum[j]-sum[i])));

对于dp[i][j][1]同理。

dp[i][j][1]也只会从dp[i][j-1][0/1]转移过来

与dp[i][j][0]转移同理

 

初始化:dp[i][i][0/1]=INF,dp[c][c][0/1]=0;这道题不用dp[i][j][0/1]=INF,因为dp[i][j][0/1]不需要min(dp[i][j][0/1]);

 

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back   
#define popb pop_back  
#define fi first
#define se second
const int N=110;
//const int M=;
//const int inf=0x3f3f3f3f;     
const ll INF=0x3ffffffffffff;
int T,n,c,pos[N],w[N];
ll dp[N][N][3],sum[N];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int main()
{
//    freopen("","r",stdin);
//    freopen("","w",stdout);
    n=read(),c=read();
    for(int i=1;i<=n;i++)
    {
        pos[i]=read();w[i]=read();
        sum[i]=sum[i-1]+w[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) dp[i][i][0]=dp[i][i][1]=INF;
    dp[c][c][0]=dp[c][c][1]=0;
    for(int len=2;len<=n;len++)
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            dp[i][j][0]=min(dp[i+1][j][0]+(pos[i+1]-pos[i])*(sum[n]-(sum[j]-sum[i])),
                            dp[i+1][j][1]+(pos[j]-pos[i])*(sum[n]-(sum[j]-sum[i])));
            dp[i][j][1]=min(dp[i][j-1][0]+(pos[j]-pos[i])*(sum[n]-(sum[j-1]-sum[i-1])),
                            dp[i][j-1][1]+(pos[j]-pos[j-1])*(sum[n]-(sum[j-1]-sum[i-1])));
        }
    printf("%lld",min(dp[1][n][0],dp[1][n][1]));
    return 0;
}
posted @ 2023-03-05 20:31  QAQ啥也不会  阅读(9)  评论(0编辑  收藏  举报