【洛谷1220】关路灯

题目链接:https://www.luogu.org/problem/show?pid=1220
题解:
- 我们发现它关的路灯一定是一个连续的区间,而且关掉一个区间的灯时,这个人一定在区间的左端点和右端点,那么我们考虑可以拿区间DP做
- 用 f[i][j][0/1] 表示关掉 [i,j] 区间的灯时花费的最少的功耗,0/1表示人此时在左端/右端,那么只要求一个功率的前缀和就能 O(1) 地转移,
dp方程推一推就出来了

/*f[i][j][0]=min(
                f[i+1][j][0]+(pos[i+1]-pos[i])*(sum[i]+sum[n]-sum[j]),
                f[i+1][j][1]+(pos[j]-pos[i])*(sum[i]+sum[n]-sum[j])
              )
f[i][j][1]=min(
                f[i][j-1][0]+(pos[j]-pos[i])*(sum[i-1]+sum[n]-sum[j-1]),
                f[i][j-1][1]+(pos[j]-pos[j-1])*(sum[i-1]+sum[n]-sum[j-1])
              ) */
//by sdfzchy
#include
#include
#include
#include
using namespace std;
const int N=60;
int f[100][100][2],n,w[N],pos[N],c,sum[N];


int main()
{
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++) scanf("%d%d",&pos[i],&w[i]),sum[i]=sum[i-1]+w[i];
    memset(f,0x3f,sizeof(f));
    f[c][c][0]=f[c][c][1]=0;
    for(int i=c+1;i<=n;i++)
    {
        f[c][i][1]=f[c][i-1][1]+(pos[i]-pos[i-1])*(sum[n]-sum[i-1]+sum[c-1]);
        f[c][i][0]=f[c][i][1]+(pos[i]-pos[c])*(sum[n]-sum[i]+sum[c-1]);
    }
    for(int i=c-1;i;i--)
    {
        f[i][c][0]=f[i+1][c][0]+(pos[i+1]-pos[i])*(sum[i]+sum[n]-sum[c]);
        f[i][c][1]=f[i][c][0]+(pos[c]-pos[i])*(sum[i-1]+sum[n]-sum[c]);
    }

    for(int i=c-1;i;i--)
        for(int j=c+1;j<=n;j++)
        {
            f[i][j][0]=min(f[i+1][j][0]+(pos[i+1]-pos[i])*(sum[i]+sum[n]-sum[j]),f[i+1][j][1]+(pos[j]-pos[i])*(sum[i]+sum[n]-sum[j]));
            f[i][j][1]=min(f[i][j-1][0]+(pos[j]-pos[i])*(sum[i-1]+sum[n]-sum[j-1]),f[i][j-1][1]+(pos[j]-pos[j-1])*(sum[i-1]+sum[n]-sum[j-1]));  
        }           
    printf("%d\n",min(f[1][n][0],f[1][n][1]));
    return 0;       
}

你可能感兴趣的:(动态规划,-,区间DP)