Monkey Party
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 953 Accepted Submission(s): 418
Now there are n monkeys sitting in a circle, and each monkey has a making friends time. Also, each monkey has two neighbor. SDH wants to introduce them to each other, and the rules are:
1.every time, he can only introduce one monkey and one of this monkey's neighbor.
2.if he introduce A and B, then every monkey A already knows will know every monkey B already knows, and the total time for this introducing is the sum of the making friends time of all the monkeys A and B already knows;
3.each little monkey knows himself;
In order to begin the party and eat bananas as soon as possible, SDH want to know the mininal time he needs on introducing.
8 5 2 4 7 6 1 3 9
105
刚学习四边形不等式优化,可以将一类特殊的O(n^3)复杂度的dp降为O(n^2),
地址:http://wenku.baidu.com/link?url=BIsI68PqTBa4fCwpNjGQd8lPKRNwaWn1EYzCRvEvpq_hq6FwnC7KFg4Wmpo_Nf_9GeDm8kqoVpEzFyRekAmCqj1vBcZfk5CPxHVVgM9eqAO
定义状态dp[i][j]为使第i只到第j只猴子互相认识的最少时间,显然有 dp[i][j] =min{ dp[i][k]+dp[k+1][j], i<=k<=j-1}+(sum[j]-sum[i-1] ) (sum[i]为前i项和)。这个基本和四边形不等式可以优化的形式一致,这里的sum[j]-sum[i-1]就是等价于w[i,j]。
显然满足区间单调性w[i',j]<=w[i,j'],和四边形不等式w[i,j]+w[i',j']<=w[i,j']+w[i',j]
因此可以优化为dp[i][j] = min{dp[i][k]+dp[k+1][j], s[i][j-1]<=k<=s[i+1][j]}+w[i,j]。其中s[i,j]是区间[i,j]取得最值的决策变量(即k),并满足单调性s[i,j-1]<=s[i,j]<=s[i+1,j]。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1001
#define inf 0x3f3f3f3f
typedef long long ll;
ll dp[2*maxn][2*maxn]; //因为1和n是neighbour,即是循环的,因此在第n项后重复添加第1到n-1项
ll sum[2*maxn];
int s[2*maxn][2*maxn];
int n;
int main()
{
while(~scanf("%d", &n)){
memset(dp, inf, sizeof(dp));
sum[0]= 0;
for(int i = 1; i <= n; i++){
scanf("%I64d", sum+i);
sum[i] += sum[i-1];
s[i][i] = i;
dp[i][i] = 0;
}
for(int i = n+1; i <= 2*n-1; i++){
sum[i] = sum[i-1]+(sum[i-n]-sum[i-n-1]);
s[i][i] = i;
dp[i][i] = 0;
}
for(int len = 1; len <= n-1; len++){
for(int i = 1; i <= n; i++){
int k = i+len;
int t, mini = inf;
for(int j = s[i][k-1]; j <=s[i+1][k]; j++){
if(dp[i][j]+dp[j+1][k]<=mini){ t = j; mini = dp[i][j]+dp[j+1][k];}
}
s[i][k] = t;
dp[i][k] = mini+sum[k]-sum[i-1];
}
}
ll ans = inf;
for(int i = 1; i <= n; i++)
ans = min(ans, dp[i][i+n-1]);
printf("%I64d\n",ans);
}
return 0;
}