http://acm.hdu.edu.cn/showproblem.php?pid=4283
题意:
有n个人,每个人有个不开心值v,现在排队表演,对于某人来说如果他排在第k个,那么他的不开心值就为(k-1)*v。现在有个小黑屋,相当于栈,可以改变队伍的顺序,计算出最小的不开心值和。
思路:
dp【i】【j】表示从第i个人到第j个人这段区间的最小花费(是只考虑这j-i+1个人,不需要考虑前面有多少人)
那么对于dp【i】【j】的第i个人,他可以在任何位置上场。现在考虑第K个上场 那么i+1之后的K-1个人是率先上场的,那些人的不开心值就是dp【i+1】【i+k-1】。
对于第i个人,由于是第k个上场的,他的不开心值就是a[i]*(k-1) 。
其余的人是排在第k+1个之后出场的,也就是dp【i+k】【j】,由于他们要等前面的k个人,所有此时不开心值还要额外加上k*(sum【j】-sum【i+k-1】)。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,int> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn = 100 + 5; 17 18 int n; 19 int a[maxn]; 20 int sum[maxn]; 21 int d[maxn][maxn]; 22 23 int main() 24 { 25 //freopen("in.txt","r",stdin); 26 int T; 27 int kase=0; 28 scanf("%d",&T); 29 while(T--) 30 { 31 sum[0]=0; 32 33 scanf("%d",&n); 34 35 memset(d,0,sizeof(d)); 36 for(int i=1;i<=n;i++) 37 { 38 for(int j=i+1;j<=n;j++) 39 d[i][j]=INF; 40 } 41 42 for(int i=1;i<=n;i++) 43 { 44 scanf("%d",&a[i]); 45 sum[i]=sum[i-1]+a[i]; 46 } 47 48 for(int r=2;r<=n;r++) 49 { 50 for(int i=1;i+r-1<=n;i++) 51 { 52 int j=i+r-1; 53 for(int k=i;k<=j;k++) 54 { 55 d[i][j]=min(d[i][j],d[i+1][k]+d[k+1][j]+a[i]*(k-i)+(sum[j]-sum[k])*(k-i+1)); 56 } 57 } 58 } 59 printf("Case #%d: %d ",++kase,d[1][n]); 60 } 61 return 0; 62 }