题目大意:有n盏灯,每盏灯有功耗和位置。一个人在第c盏灯处,要关闭所有灯,问灯在关闭前总功耗为多少。
解题思路:dp。
首先我们可以知道,关的灯总是一个连续的区间,因为如果中间空了一个灯,还不如走过去时顺便关了它。
其次,关掉一个区间的灯后,人总是在区间最左边或最右边。
那么我们设f[i][j][0]表示关掉i~j这些灯后站在左端的最小功耗,f[i][j][1]表示关掉i~j这些灯后站在右端的最小功耗。
那么有f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[n]-(sum[j]-sum[i])),f[i+1][j][1]+(a[j]-a[i])*(sum[n]-(sum[j]-sum[i])))
f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[n]-(sum[j-1]-sum[i-1])),f[i][j-1][1]+(a[j]-a[j-1])*(sum[n]-(sum[j-1]-sum[i-1])))
于是最后答案为min(f[1][n][0],f[1][n][1])。
C++ Code:
#include<cstdio> #include<cstring> using namespace std; int f[55][55][2],n,c,sum[55]; int a[55]; inline int min(int x,int y){return(x<y)?x:y;} int main(){ memset(f,0x3f,sizeof f); scanf("%d%d",&n,&c); sum[0]=0; for(int i=1;i<=n;++i){ int t; scanf("%d%d",&a[i],&t); sum[i]=sum[i-1]+t; } f[c][c][0]=f[c][c][1]=0; for(int i=1;i<=n;++i){ int l=c-i; if(l<1)l=1; for(int j=l;j<=c;++j){ int k=j+i; f[j][k][0]=min(f[j+1][k][0]+(a[j+1]-a[j])*(sum[n]-(sum[k]-sum[j])), f[j+1][k][1]+(a[k]-a[j])*(sum[n]-(sum[k]-sum[j]))); f[j][k][1]=min(f[j][k-1][0]+(a[k]-a[j])*(sum[n]-(sum[k-1]-sum[j-1])), f[j][k-1][1]+(a[k]-a[k-1])*(sum[n]-(sum[k-1]-sum[j-1]))); } } printf("%d ",min(f[1][n][0],f[1][n][1])); return 0; }