您的位置:首页 > 其它

HDOJ 2829 Lawrence(斜率优化DP)

2017-04-30 23:55 357 查看
Lawrence
Time Limit: 2000/1000 MS(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3979    Accepted Submission(s): 1804


Problem Description
T. E. Lawrence was acontroversial figure during World War I. He was a British officer who served inthe Arabian theater and led a group of Arab nationals in guerilla strikesagainst the Ottoman Empire. His primary
targets were the railroads. A highly fictionalizedversion of his exploits was presented in the blockbuster movie, "Lawrenceof Arabia".

You are to write a program to help Lawrence figure out how to best use hislimited resources. You have some information from British Intelligence. First,the rail line is completely linear---there are no branches, no spurs. Next,British Intelligence has assigned
a Strategic Importance to each depot---aninteger from 1 to 100. A depot is of no use on its own, it only has value if itis connected to other depots. The Strategic Value of the entire railroad iscalculated by adding up the products of the Strategic Values
for every pair ofdepots that are connected, directly or indirectly, by the rail line. Considerthis railroad:



Its Strategic Value is 4*5 + 4*1 + 4*2 + 5*1 + 5*2 + 1*2 = 49.

Now, suppose that Lawrence only has enough resources for one attack. He cannotattack the depots themselves---they are too well defended. He must attack therail line between depots, in the middle of the desert. Consider what wouldhappen if Lawrence attacked
this rail line right in the middle:

The Strategic Value of the remaining railroad is 4*5 + 1*2 = 22. But, supposeLawrence attacks between the 4 and 5 depots:



The Strategic Value of the remaining railroad is 5*1 + 5*2 + 1*2 = 17. This isLawrence's best option.



Given a description of a railroad and the number of attacks that Lawrence canperform, figure out the smallest Strategic Value that he can achieve for thatrailroad.

 
 
Input
There will be several datasets. Each data set will begin with a line with two integers, n and m. n is thenumber of depots on the railroad (1≤n≤1000), and m is the number of attacksLawrence has resources for (0≤m<n).
On the next line will be n integers,each from 1 to 100, indicating the Strategic Value of each depot in order. Endof input will be marked by a line with n=0 and m=0, which should not beprocessed.

 
 
Output
For each data set, output asingle integer, indicating the smallest Strategic Value for the railroad thatLawrence can achieve with his attacks. Output each integer in its own line.

 
 
Sample Input
4 1
4 5 1 2
4 2
4 5 1 2
0 0
 
 
Sample Output
17
2
 

斜率优化DP的经典题目

我们用dp[i][x]表示前i个点,炸掉x条边可以破坏的最大值,用tot表示没炸过是的值,则结果为tot
-dp
[m]

写出状态转移方程:dp[i][x]=max{dp[j][x-1]+sum[j]*(sum[i]-sum[j])}   ( x-1<j<i)

假设k<j<i,且在j点比在k点更优,那么dp[k][x-1]+sum[k]*(sum[i]-sum[k])<=dp[j][x-1]+sum[j]*(sum[i]-sum[j])

=》( (sum[j]*sum[j]-dp[j][x-1])-(sum[k]*sum[k]-dp[k][x-1]) ) /(sum[j]-sum[k] ) <=sum[i]

令yj=sum[j]*sum[j]-dp[j][x-1], yk=sum[k]*sum[k]-dp[k][x-1];
xj=sum[j], xk=sum[k];

则原方程转化为(yj-yk)/(xj-xk)<=sum[i];

左边即为斜率表示,用单调队列维护斜率即可

#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
const int maxn = 1005;
const int mod = 9973;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define ll long long
#define rush() int T;scanf("%d",&T);while(T--)
int n,m;
int a[maxn],sum[maxn];
int q[maxn];
int dp[maxn][maxn];
int tot;

int getdp(int i,int x,int j)
{
return dp[j][x-1]+sum[j]*(sum[i]-sum[j]);
}

int getup(int j,int x,int k)
{
return sum[j]*sum[j]-dp[j][x-1]-(sum[k]*sum[k]-dp[k][x-1]);
}

int getdown(int j,int k)
{
return sum[j]-sum[k];
}

int main()
{
int head,tail;
while(~scanf("%d%d",&n,&m)&&(n||m))
{
sum[0]=0;
mst(dp,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
tot=0;
for(int i=n;i>1;i--)
tot+=a[i]*sum[i-1];
head=tail=0;
for(int i=1;i<=m;i++)
{
head=tail=0;
q[tail++]=i;
for(int j=i+1;j<=n;j++)
{
while(head+1<tail&&getup(q[head+1],i,q[head])<=sum[j]*getdown(q[head+1],q[head]))
head++;
dp[j][i]=getdp(j,i,q[head]);
while(head+1<tail&&getup(j,i,q[tail-1])*getdown(q[tail-1],q[tail-2])<=getup(q[tail-1],i,q[tail-2])*getdown(j,q[tail-1]))
tail--;
q[tail++]=j;
}
}
printf("%d\n",tot-dp
[m]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: