Monkey Party
题意:n个猴子围成一圈,猴王每次将两个猴子相互介绍认识,每次介绍时,两个猴子原来认识的也就都认识了,每次介绍花费时间时两个猴子所认识的的权值之和, 每次只能相邻猴子介绍,问最少花费时间;
思路:其实就是环形的合并石子,一模一样,就是把石子改成了猴子,n堆石子扩展为2n堆合并,最后找合并长度时n的;
然后思如泉涌就写完了,,,,,T了!!!!一看数据,恍然大明白,1000个猴,复杂度O(n^3),T是没跑了;
咋办哪!!!!!!!
在区间DP中有个优化,四边形不等式加速,优化后是O(n^2)的复杂度;
令s[i][j]=max( k | min(dp[i][j])(i<=k<=j));这个式子是不是很懵逼?表示使dp[i][j]最小的最大k;
则dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum[i][j] | s[i][j-1] <=k<= s[i+1][j]);
虽然还是三层循环,但是复杂度是O(n^2)的;
证明我还真不会~~~
欲知详情,请百度:动态规划加速原理之四边形不等式
赵爽老师写的,还算不错,虽然没看懂证明,,,,但是会简单运用了,,,,数学还是硬伤啊!!!!
#include <bits/stdc++.h>
#define INF 0x7f7f7f7f
using namespace std;
typedef long long ll;
ll t[2100], dp[2100][2100], s[2100][2100], sum[2100];
int main(){
int n;
while(~scanf("%d", &n)){
memset(dp, INF, sizeof(dp));
for(int i=1; i<=n; i++){
scanf("%d", &t[i]);
t[i+n]=t[i];
}
sum[0]=0;
for(int i=1; i<=2*n; i++){
sum[i]=sum[i-1]+t[i];
dp[i][i]=0;
s[i][i]=i;
}
for(int len=2; len<=n; len++){
for(int i=1; i+len-1<=2*n; i++){
int j=i+len-1;
for(int k=s[i][j-1]; k<=s[i+1][j]; k++){
ll temp=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
if(dp[i][j]>=temp){
dp[i][j]=temp;
s[i][j]=k;
}
}
}
}
ll ans=INF;
for(int i=1; i<=n; i++){
ans=min(ans, dp[i][i+n-1]);
}
printf("%d\n", ans);
}
return 0;
}