HDU 4283 You Are the One 区间dp
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4283
You Are the One
Memory Limit: 32768/32768 K (Java/Others)
输入
The first line contains a single integer T, the number of test cases. For each case, the first line is n (0 < n <= 100)
The next n line are n integer D1-Dn means the value of diaosi of boys (0 <= Di <= 100)
输出
For each test case, output the least summary of unhappiness .
样例输入
2
5
1
2
3
4
55
5
4
3
2
2
样例输出
Case #1: 20
Case #2: 24
题意
n个人排成一排,每个人的生气值是arr[i]*(排在他前面的人数),现在按123...n的顺序进栈,现在要你调整出一种合法的出栈顺序使得所有人的生气值总和最小。
题解
区间dp(根据栈的性质)
对于区间[L,R]我们考虑最前面的人(L),是这个区间里面第K个出栈的,那么就有[L+1,K]个人要先于L出栈,[K+1,R]的人要后于L出栈,这样就吧一个区间分解成两个子区间了。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=222;
int dp[maxn][maxn],arr[maxn];
int sumv[maxn];
int dfs(int l,int r){
if(l>=r) return 0;
if(dp[l][r]>=0) return dp[l][r];
int &res=dp[l][r]=INF;
for(int i=l;i<=r;i++){
int fi=dfs(l+1,i);
int se=dfs(i+1,r)+(sumv[r]-sumv[i])*(i-l+1);
int cur=arr[l]*(i-l);
res=min(res,fi+se+cur);
}
return res;
}
int n;
int main() {
int tc,kase=0;
scf("%d",&tc);
while(tc--){
clr(dp,-1);
scf("%d",&n);
sumv[0]=0;
for(int i=1;i<=n;i++){
scf("%d",&arr[i]);
sumv[i]=sumv[i-1]+arr[i];
}
prf("Case #%d: %d\n",++kase,dfs(1,n));
}
return 0;
}
//end-----------------------------------------------------------------------
Notes
当一点头绪都没有的时候,先尝试去固定一些变量,比如这一题,你如果想到先去安排最前面一个人在第k个出来的情况,你就会发现这题可以用区间dp来写。