【问题描述】
你是一个公司的员工,你会按时间顺序受到一些产品的订单,你需要用一个栈来改变这些订单的顺序(每个产品都必须入栈和出栈一次)。
按初始顺序,每次可以将一个产品入栈,或将栈顶产品弹至现在的序列末尾。每个产品有一个制作时间t i 和单位时间惩罚值d i 。
总的惩罚值为∑ ni=1 (s i × d i ),其中s i 为第i个产品的完成时间,你需要最小化总的惩罚值。
【输入】
输入文件 product.in。
第一行一个数n,表示产品个数。
接下来n行,每行两个数表示t i , d i 。
【输出】
输出文件 product.out。
一行一个数表示最小的总惩罚值。【样例输入】
4
1 4
3 2
5 2
2 1
【样例输出】
40
【数据范围】
30%: n ≤ 15
50%: n ≤ 100
100%: n ≤ 200, t i , d i ≤ 1000
正解:
f[l][r] : 标号 l~r 的最小惩罚值 (时间上以开始生产[ l , r ]的产品为起始)
< st[ ] 为时间前缀和 sd[ ] 为单位时间惩罚值前缀和>
在[l,r] 中枚举 i , i 为 [l,r]中最后一个出栈的元素 即栈中最后一个元素
f[l][r]=min(f[l][r],f[l][i-1]+f[i+1][r]+(st[i-1]-st[l-1])*(sd[r]-sd[i])+(st[r]-st[l-1])*d[i]);
这个转移方程式我真的想了差不多十分钟才看懂
如下:(一定要仔细,耐心理解 qwq)
i 为最后一个出栈的元素 所以 l ~ i-1 一定在 i 进栈前就出栈了(否则它们现在就还在栈中)
f[l][i-1] 和 f[i+1][r] 都只与它们内部的顺序以及 [ l , i ]的总时间有关
是两个互不相关的子问题
(st[r]-st[l-1])*d[i]) 是 i 的惩罚值 很好理解
(st[i-1]-st[l-1])*(sd[r]-sd[i]) 我觉得是一个很巧妙的地方啊
我觉得我现在说不清楚 要自己领会一下qwq
但是我还是要大概说一下<这里用记忆化搜索实现的>
是加法结合律的逆向运用
然后保证了计算f[i+1][r]的时间是包括[l,r]中比它们先出去的产品的完成时间的
至于内部的顺序问题 又到下一层函数解决了
层层递归
CODE
std View Code 非记搜1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 #define LY(p) freopen (p".in", "r", stdin); freopen (p".out", "w", stdout) 9 #define LL long long 10 #define dbl double 11 #define lf long double 12 #ifdef WIN32 13 #define L_L "%I64d" 14 #else 15 #define L_L "%lld" 16 #endif 17 #define N 210 18 int n, t[N], d[N], st[N], sd[N]; 19 LL f[N][N]; 20 21 int main() 22 { 23 scanf ("%d", &n); 24 for (int i = 1; i <= n; i++) { 25 scanf ("%d %d", &t[i], &d[i]); 26 st[i] = st[i - 1] + t[i]; 27 sd[i] = sd[i - 1] + d[i]; 28 } 29 30 memset (f, 0x3f, sizeof (f)); 31 for (int i = 1; i <= n; i++) 32 f[i][i] = d[i] * t[i], f[i][i - 1] = 0; 33 f[n + 1][n] = 0; 34 35 for (int l = 1; l < n; l++) 36 for (int i = 1; i + l <= n; i++) 37 { 38 int j = i + l; 39 for (int k = i; k <= j; k++) 40 f[i][j] = min 41 (f[i][k - 1] + f[k + 1][j] + 1LL * (st[k - 1] - st[i - 1]) * (sd[j] - sd[k]) + 1LL * (st[j] - st[i - 1]) * d[k], f[i][j]); 42 } 43 44 printf (L_L, f[1][n]); 45 return 0; 46 }dtt View Code 记搜1 #include<iostream> 2 #include<cstdio> 3 #define go(i,a,b) for(register int i=a;i<=b;i++) 4 #define ll long long 5 #define M 201 6 #define inf 21000000000000 7 using namespace std; 8 ll read() 9 { 10 int x=0,y=1;char c=getchar(); 11 while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();} 12 while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();} 13 return x*y; 14 } 15 ll n,t[M],d[M],st[M],sd[M],f[M][M]; 16 ll dfs(int l,int r) 17 { 18 if(l>r) return 0; 19 if(l==r) return t[l]*d[l]; 20 if(f[l][r]) return f[l][r]; 21 f[l][r]=inf; 22 go(i,l,r) 23 f[l][r]=min(f[l][r],dfs(l,i-1)+dfs(i+1,r)+(st[r]-st[l-1])*d[i]+(st[i-1]-st[l-1])*(sd[r]-sd[i])); 24 return f[l][r]; 25 } 26 int main() 27 { 28 n=read(); 29 go(i,1,n) 30 { 31 t[i]=read();st[i]=st[i-1]+t[i]; 32 d[i]=read();sd[i]=sd[i-1]+d[i]; 33 } 34 printf("%lld",dfs(1,n)); 35 return 0; 36 }