标签:链接 整数 col 适合 php ack scan eof back
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4261
题意:给出一个序列A,分为K个部分,然后每个部分给出一个B,使得所有的sigma(|Ai-Bi|)最小
解题思路:首先定义状态dp【i】【j】:前i个分成j块的最小代价。那么很容易得到dp【i】【j】=min(dp【m】【i-1】+(m+1到i分成一块的代价))。那么问题的关键就成了求出所有可能的区间分成一块的代价了。对于每个区间,很容易想到:把B数组的这个块赋值为相应A数组的块的中位数了,此时代价最小。至于怎么求中位数,可以定义两个优先队列,一个值大的优先,一个值小的优先,那每个区间平均放到这两个队列,那么中位数就为这两个区间队首的某一个了,接着求这个区间的代价就可以了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+5;
int dp[maxn][30];
int tem[maxn][maxn];
int a[maxn];
const int inf=0x3f3f3f3f;
priority_queue<int,vector<int>,greater<int> >que1;
priority_queue<int> que2;
int main(){
int n,k;
while(scanf("%d%d",&n,&k)!=EOF){
if(n==0&&k==0){
return 0;
}
for(int i=0;i<=n;i++){
for(int j=1;j<=k;j++){
dp[i][j]=inf;
}
dp[i][i]=0;
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
while(!que1.empty())que1.pop();
while(!que2.empty())que2.pop();
int sum1,sum2;
sum1=sum2=0;
for(int j=i;j>=1;j--){
int l1=(i-j+2)/2;
int l2=(i-j+1)/2;
int t=a[j];
if(que1.empty()){
sum1+=t;
que1.push(t);
}
else{
if(t>que1.top()){
sum1+=t-que1.top();
que1.push(t);
t=que1.top();
que1.pop();
}
if(!que2.empty()&&t<que2.top()){
sum2+=t-que2.top();
que2.push(t);
t=que2.top();
que2.pop();
}
if(que1.size()<l1){
sum1+=t;
que1.push(t);
}
else{
sum2+=t;
que2.push(t);
}
}
t=que1.top();
int t1=-1;
if(!que2.empty())
t1=que2.top();
if((i-j+1)&1){
tem[j][i]=sum1-t*l1+t*l2-sum2;
}
else{
tem[j][i]=min(sum1-t*l1+t*l2-sum2,sum1-t1*l1+t1*l2-sum2);
}
}
}
for(int i=1;i<=n;i++){
dp[i][1]=tem[1][i];
}
for(int i=2;i<=k;i++){
for(int j=i;j<=n;j++){
for(int m=1;m<j;m++){
dp[j][i]=min(dp[j][i],dp[m][i-1]+tem[m+1][j]);
}
}
}
printf("%d\n",dp[n][k]);
}
return 0;
}
标签:链接 整数 col 适合 php ack scan eof back
原文地址:https://www.cnblogs.com/Zhi-71/p/11862522.html