P1220 关路灯
考察:区间dp
这题好像HDU 4283 可以往左或者往右走.但是这道题起始位置不确定,也就是说,i位置不一定是栈底.
思路:
因为题目完全不一样,所以必须换一个思路.以f[i][j]表示灭掉[i,j]所有灯消耗的功率.首先明确老张灭灯只要路过了就会灭,因此最后的位置要么是左边要么是右边.这两边难以确定,所有要用状态记录.
f[l][r][1]表示最后位置在[l,r]区间的r处,需要推到此状态可以由哪些状态转移而来.
f[l][r][1] = f[l][r-1][0] + (s[r]-s[r-1])*(sum[l-1]+sum[n]-sum[r-1])//(从r-1->r的时间后,其他灯等待的时间)
f[l][r][0] = f[l][r-1][1]+ (s[r]-s[l])*(sum[l-1]+sum[n]-sum[r-1])//(从l->r的时间后,其他灯等待的时间)
大区间由小区间推导而来,记录一下dp方程如何推导之大佬想法:
填表法就是利用状态转移方程和上一个状态来推导出现在的状态(相当于知道已知条件,将答案填入)
刷表法就是利用当前的状态,把有关联的下一状态都推出来。
明确将当前状态当成最终状态,因此终状态只能由子状态推导而来.
记忆化搜索会TLE,或者是我没写对....
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 55,INF = 0x3f3f3f3f; 6 int n,s[N],sum[N],f[N][N][2],m; 7 void solve() 8 { 9 for(int len=2;len<=n;len++) 10 for(int l=1;l+len-1<=n;l++) 11 { 12 int r = l+len-1; 13 int a = f[l+1][r][0]+(s[l+1]-s[l])*(sum[l]+sum[n]-sum[r]); 14 int b = f[l+1][r][1]+(s[r]-s[l])*(sum[l]+sum[n]-sum[r]); 15 f[l][r][0] = min(a,b); 16 int c = f[l][r-1][0]+(s[r]-s[l])*(sum[l-1]+sum[n]-sum[r-1]); 17 int d = f[l][r-1][1]+(s[r]-s[r-1])*(sum[l-1]+sum[n]-sum[r-1]); 18 f[l][r][1] = min(c,d); 19 } 20 } 21 int main() 22 { 23 scanf("%d%d",&n,&m); 24 memset(f,0x3f,sizeof f); 25 for(int i=1;i<=n;i++) 26 { 27 scanf("%d%d",&s[i],&sum[i]); 28 sum[i]+=sum[i-1]; 29 } 30 f[m][m][0] = f[m][m][1] = 0; 31 solve(); 32 printf("%d\n",min(f[1][n][0],f[1][n][1])); 33 return 0; 34 }