-
G - You Are the One
HDU - 4283 - 想了好久才明白题意。
- 题意:有n个人排成一排要上台表演,每个人有一个屌丝值pi。第i个上台表演的人,他的不满意度为(i-1)*pi。
- 现在有一个栈类型的屋子。这些人要按照排的顺序来,那么对于排在最前面的人,
- 就有两个选择:
- (1)让他直接上台表演;
- (2)让他暂时进黑屋子。
- 思路:不可以是有规则的调整不可以贪心解决。
- 转自:https://blog.csdn.net/libin56842/article/details/9722077?utm_source=copy
- dp[i][j]表示从第i个人到第j个人这段区间的最小花费(是只考虑这j-i+1个人,不需要考虑前面有多少人) 那么对于dp[i][j]的第i个人,就有可能第1个上场,也可以第j-i+1个上场。考虑第K个上场 即在i+1之后的K-1个人是率先上场的,那么就出现了一个子问题 dp[i+1][i+k-1]表示在第i个人之前上场的 对于第i个人,由于是第k个上场的,那么屌丝值便是a[i]*(k-1) 其余的人是排在第k+1个之后出场的,也就是一个子问题dp[i+k][j],对于这个区间的人,由于排在第k+1个之后,所以整体愤怒值要加上k*(sum[j]-sum[i+k-1])
- 区间dp有所变化
- ①枚举区间长度②枚举起点③由于dp[i][j]表示从第i个人到第j个人这段区间的最小花费所以枚举k代表i是第k个上场的
- 递推:
-
#include<bits/stdc++.h> using namespace std; #define maxn 111 #define inf 0x3f3f3f3f int n,a[maxn],t,T; int dp[maxn][maxn]; int pre[maxn]; int main() { cin>>T; for(int t=1; t<=T; t++) { cin>>n; for(int i=1; i<=n; i++) { cin>>a[i]; pre[i]=pre[i-1]+a[i]; } for(int len=0; len<n; len++) for(int i=1; i+len<=n; i++) { int j=i+len; dp[i][j]=inf; for(int k=1; k<=j-i+1; k++) dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+a[i]*(k-1)+k*(pre[j]-pre[i+k-1])); } cout<<"Case #"<<t<<": "<<dp[1][n]<<endl; } return 0; }
- 记忆化搜索:
-
#include<bits/stdc++.h> using namespace std; #define maxn 111 #define inf 0x3f3f3f3f int n,a[maxn],t,T; int dp[maxn][maxn]; int pre[maxn]; int dfs(int l,int r) { if(dp[l][r]!=-1) return dp[l][r]; if(l>r) return 0; int ans=inf; for(int k=1; k<=r-l+1; k++) ans=min(ans,dfs(l+1,l+k-1)+dfs(l+k,r)+a[l]*(k-1)+(pre[r]-pre[l+k-1])*k); return dp[l][r]=ans; } int main() { cin>>T; for(int t=1; t<=T; t++) { cin>>n; for(int i=1; i<=n; i++) { cin>>a[i]; pre[i]=pre[i-1]+a[i]; } memset(dp,-1,sizeof(dp)); dfs(1,n); cout<<"Case #"<<t<<": "<<dp[1][n]<<endl; } return 0; }
G - You Are the One-区间dp
最新推荐文章于 2021-09-27 13:32:50 发布