dp slope optimization

Original link: https://blog.csdn.net/qq_41730082/article/details/86305056

list[0]=0

The initial value is extremely large, it will be more of a M value, taking into account the initial value problem, is to put the head of the queue to 0, this is the case, you can solve the above problem, otherwise, it will continue the walk to the top, but initially will be more out of a M.

  The rest is optimized template slope of the DP, but to talk about the specific formula of reasoning:

对于dp[i] = min( (sum[i] - sum[j])^2 + M + dp[j] );(j < i)

dp[i] = min( sum[i]^2 + sum[j]^2 - 2*sum[i]*sum[j] + M + dp[j] );

In order to find the optimal prior to i j, we assume that there exists such a k <j <i, j is the optimal solution but prior to i, then there are:

sum[i]^2 + sum[j]^2 - 2*sum[i]*sum[j] + M + dp[j] < sum[i]^2 + sum[k]^2 - 2*sum[i]*sum[k] + M + dp[k];

Be simplification, will be:

sum[j]^2 - 2*sum[i]*sum[j] + dp[j] < sum[k]^2 - 2*sum[i]*sum[k] + dp[k];

We then moved with the value of i to one side, so there are:

sum[j]^2 + dp[j] - ( sum[k]^2 + dp[k] ) < 2 * sum[i] * ( sum[j] - sum[k] );

Thus, it may be assumed to get a beveled formula:

( sum[j]^2 + dp[j] - ( sum[k]^2 + dp[k] ) ) / (2 * ( sum[j] - sum[k] )) < sum[i];

So, assuming that the slope of this expression:

Order yj = sum [j] ^ 2 + dp [j]; Order yk = sum [k] ^ 2 + dp [k];

So that xj = 2 * sum [j]; Order xk = 2 * sum [k];

Thus, the original formula is equal to: (yj - yk) / (xj - xk) <[i] sum;

In this case, j is better than k, we accordance with this inequality, we can write columns of monotonous queue,

Among 0 ~ j, j must be optimal solution is recorded as sum prefix and, therefore, it is a monotonically increasing, there is a sum [i + x]> sum [i]> (yj - yk) / ( xj - xk);

So, the next point to consider only between i + 1 ~ i + x, and if there is such a better solution between, then, j this node do not need to save, and we jpop () wants in this case, the team point i, i point and comparison point end of the queue q [tail], q slope [tail-1] is: K1, K2;

If K1 <= K2, then q [tail] removing it, then this is certainly not the point of use, because it is no previous node of its superiority, so we compare one by one, until the queue node is not remaining the time (in fact, it would be the rest of a node 0 we initially placed to ensure that the situation may be the first one from the start plus the backward elements), or K1> K2, we end the cycle, and continue to the next element.

By the way, after the head treatment, there will be dp [] assignment, the first team to take at this time, because that is the optimal solution.
https://blog.csdn.net/qq_36038511/article/details/82906874

1606: [Example 1] task scheduling 1

Questions if it is with ordinary dp would you do it?
Common dp, then the complexity is O (N ^ 3), and with dp [i] [j] denotes the front i task divided j segment
so common transfer expression is: dp [i] [j] = min ( dp [i] [j], dp [k] [j-1] + (time_sum [i] + s * j) * (cost_sum [i] -cost_sum [k])) j-1 <= k <= i -1

In fact, I do not know how to push back the time, or you can write the expression of violence, look for ideas

A look that is dp, and set f [i] i minimum cost for the first two tasks.
Identify problems in s hard to deal with, there is a very good skill to use - the cost in advance .
Specifically is this: because we do not know how many before use s, so here is difficult to calculate the cost, in other words, we did not know before the current contribution, but we now know that the contribution of the future!
If the current x ~ Y together complete the task of this period, so in fact, we x ~ n this period of time to complete the task are postponed s, then directly coupled (c [n] -c [x -1]) × s, c is the task of cost factors and prefix) to.
Then derived equation: f [i] = mini ( {f [j] + (s [i] + s) × (c [i] -c [j]) + s × (c [n] -c [j ])} t is a prefix and the time spent by the task

// If this question is to use common dp would you do it? 
@ Common words dp complexity is O (N ^ 3), and with dp [i] [j] denotes the i-th task before the divided sections j 
@ Common transfer expression is then: 
// dp [i] [j] = min (dp [ i] [j], dp [k] [j-1] + (time_sum [i] + s * j) * ([i] cost_sum -cost_sum [k])) j-1 <= K <=. 1-i 
/ * 
a look that is dp, the set f [i] for the minimum cost of the task before the i. 
Identify problems in s hard to deal with, there is a very good skill to use - the cost in advance. 
Specifically is this: because we do not know how many before use s, so here is difficult to calculate the cost, in other words, we did not know before the current contribution, but we now know that the contribution of the future! 
If the current x ~ Y together complete the task of this period, so in fact, we x ~ n this period of time to complete the task are postponed s, then directly coupled (c [n] -c [x -1]) × s, c is the task of cost factors and prefix) to. 
Then derived equation: f [i] = mini ( {f [j] + (s [i] + s) × (c [i] -c [j]) + s × (c [n] -c [j ])} t is a prefix and the time spent by the task 
* / 
// prefix obtained T and F and st and sf, provided f [i] denotes the i-th minimum cost before completion of the task, f [i] = min ( f [i], f [j ] + st [i] (sf [i] -sf [j]) + s (st [n] -st [j])), because the have the s j + 1 ~ n tasks impact so early accumulation. 
#include <cstdio> 
#include <CString> 
#include <algorithm> 
the using namespace STD;
int list[5100];
long long f[5100],t[5100],c[5100];
int main()
{
	int n,S;
	scanf("%d%d",&n,&S);
	for (int i=1;i<=n;i++)
	{
		long long tt,cc;
		scanf("%lld%lld",&tt,&cc);
		t[i]=t[i-1]+tt;
		c[i]=c[i-1]+cc;
	}
	memset(f,63,sizeof(f));
	f[0]=0;
	for (int i=1;i<=n;i++)
	{
		for (int j=0;j<i;j++)
		{
			f[i]=min(f[j]+(t[i]+S)*(c[i]-c[j])+(c[n]-c[i])*S,f[i]);
		}
	}
	printf("%lld\n",f[n]);
	return 0;
}

1607: [Example 2] task schedule 2

Advanced practice
// While this approach on a question that is (N ^ 2) could go

j <k <i, j when k ratio preferably (Ps: C expressed for convenience Cost, T represents Time) the dp [k] + S * (C [n] -C [k]) + T [i] * ( C [i] -C [k]) <= dp [j] + S * (C [n] -C [j]) + T [i] * (C [i] -C [j])

Remove the bracket dp [k] + S * C [n] -S * C [k] + T [i] * C [i] -T [i] * C [k] <= dp [j] + S * C [n] -S * C [j] + T [i] * C [i] -T [i] * C [j]

Erasing the same dp [k] -S * C [k] -T [i] * C [k] <= dp [j] -S * C [j] -T [i] * C [j]

Transposition have dp [k] -dp [j] <= (S + T [i]) * (C [k] -C [j]) Condition 1

The (condition 1) the establishment j k than excellent, otherwise excellent ratio k j

(Dp [k] -dp [j]) / (C [k] -C [j]) is the slope

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=10010;
const int INF=0x3fffffff;
typedef long long LL;
int n,s;
LL tt[maxn],cost[maxn];
LL dp[maxn];
int que[maxn];
/*
设j<k<i,若k比j优  (Ps:为了方便C表示Cost,T表示Time)

则dp[k]+S*(C[n]-C[k])+T[i]*(C[i]-C[k])<=dp[j]+S*(C[n]-C[j])+T[i]*(C[i]-C[j])

把括号拆掉 dp[k]+S*C[n]-S*C[k]+T[i]*C[i]-T[i]*C[k]<=dp[j]+S*C[n]-S*C[j]+T[i]*C[i]-T[i]*C[j]

Erasing the same dp [k] -S * C [ k] -T [i] * C [k] <= dp [j] -S * C [j] -T [i] * C [j] 

transposing give dp [k] -dp [j] < = (S + T [i]) * (C [k] -C [j]) condition 1 

then (condition 1) when the ratio k j preferably established otherwise excellent ratio k j 

( dp [k] -dp [j] ) / (C [k] -C [j]) is the slope 
* / 
BOOL Judge (J int, int k, int I) {// J <k <I, k is determined more preferably not (dp [k] -dp [j ]) / (C [k] -C [j]) is the slope 
	int S1 DP = [K] -dp [J]; 
	int S2 = (S + TT [I ]) * (cost [K] -cost [J]); 
	return S1 <= S2. 1:? 0; 
} 
BOOL judge1 (J int, int K, int I) {// J <K <I, 
	int S1 = (DP [K] -dp [J]) * (cost [I] -cost [K]); 
	int S2 = (DP [I] -dp [K]) * (cost [K] -cost [J]) ; // exchange to see, in fact, is a division 
	return S1> = S2. 1: 0;? 
} 
int main () { 
	Scanf ( "% D% D", & n-, & S); 
	for (int I =. 1; I <= n-; I ++) { 
		int T, CC;  
		Scanf ( "% D% D",&t,&cc);
		TT [I] = TT [-I. 1] + T;
		cost[i]=cost[i-1]+cc;
	}
	dp[0]=0;
	que[1]=0;
	int head=1,tail=1;
	for(int i=1;i<=n;i++){
		while(head<tail&&judge(que[head],que[head+1],i)) head++;
		int j=que[head];
		dp[i]=dp[j]+s*(cost[n]-cost[j])+tt[i]*(cost[i]-cost[j]);
		while(head<tail&&judge1(que[tail-1],que[tail],i)) tail--;
		que[++tail]=i;
	}
	printf("%lld\n",dp[n]);
return 0;
}

  

1608: [Example 3] task scheduling 3

t array is no longer monotonic, the required half . And we still have to maintain the slope of the monotonic! ! End deleting HOL, and finally out of the list [head] is less than the slope of the left side of t [i], the slope is greater than the right t [i]

Therefore, to find the left by a slope of less than half of t [i], the slope is greater than the right t [i] point

This time Ti can be negative, so there is no monotonic up, but still monotonic convex hull of all current cutting-half point of the line and the convex hull on it (explanations original words)

#include <the iostream> 
#include <CString> 
#include <the cmath> 
#include <algorithm> 
#include <Stack> 
#include <cstdio> 
#include <Queue> 
#include <Map> 
#include <Vector> 
#include <SET> 
STD namespace the using; 
const int MAXN = 310000; 
const int = INF 0x3FFFFFFF; 
typedef Long Long LL; 
// time may be negative, so the time prefix and t [i] is not monotonic 
// we want to maintain the slope or monotonic in! ! 
// End of deleting HOL, out of the final list [head] is less than the slope of the left side of t [i], the slope is greater than the right t [i] 
// find the slope to the left so that less than t [i] by half, the right is greater than the slope of t [i] point 
// this time Ti may be negative, so there is no monotonic, but still monotonic convex hull of all current cutting-half point of the line and can be a convex hull of ( Interpretations words) 
// why two points, thought to understand 
int n-, S; 
LL DP [MAXN], T [MAXN], C [MAXN], List [MAXN];
LL Y(int i){
	return dp[i]-s*c[i];
}
double slop(int j1,int j2){
	return double(Y(j2)-Y(j1))/double(X(j2)-X(j1));
}
int main(){
	scanf("%d %d",&n,&s);
	for(int i=1;i<=n;i++){
		int tt,cc;
		scanf("%d %d",&tt,&cc);
		t[i]=t[i-1]+tt;
		c[i]=c[i-1]+cc;
	}
	int head=1,tail=1;
	list[1]=0;
	for(int i=1;i<=n;i++){
		//这里不再弹队头,因为t不具有单调性了
		int l=head,r=tail;  //二分找 
		while(l<r){
			int mid=(l+r)/2;
			if(dp[list[mid]]-dp[list[mid+1]]>=(s+t[i])*(c[list[mid]]-c[list[mid+1]])) l=mid+1;
			else r=mid;
		}
		dp[i]=dp[list[l]]-(s+t[i])*c[list[l]]+t[i]*c[i]+s*c[n];  //你仔细看,是另一种计算方法 
		while (head<=tail-1&&(dp[list[tail]]-dp[list[tail-1]])*(c[i]-c[list[tail]])>=(dp[i]-dp[list[tail]])*(c[list[tail]]-c[list[tail-1]])) tail--;
		list[++tail]=i;
	}
	printf("%lld\n",dp[n]); 
return 0;
}

1609:【例 4】Cats Transport

This becomes a two-dimensional array of dp, I think the most important thing is to think of the array a [] to sort, and then take a continuous period of transformation for everyone.

The idea is that I lack, because an increase in the number of people, the answer is finally returned dp [p] [m]

ps. Below wrong, Y () should be the sum

 

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e5+10;
const int INF=0x3fffffff;
typedef long long LL;
LL d[maxn],a[maxn],s[maxn],list[maxn];
LL dp[110][maxn];  //dp[饲养员i][收回前j只猫]
LL X(int i){
	return i;
}
LL Y(int i,int k){
	return dp[i][k]+s[k];
}
bool cmp(LL x,LL y){
	return x<y;
}
int main(){
	int n,m,p;
	scanf("%d %d %d",&n,&m,&p);
	for (int I = 2; I <= n-; I ++) { 
			the while (head <tail && (the Y (I-. 1, List [head]) -Y (i-1, list [ head + 1]))> = a [j] * (list [head] -list [head + 1])) head ++;
		Scanf ( "% D", & D [I]); 
		D [I] + = D [I-. 1]; 
	} 
	int H, T; 
	for (int I =. 1; I <= m; I ++) { 
		Scanf ( " % D% D ", & H, & T); 
		a [I] = TD [H]; 
	} 
	Sort (a +. 1, a +. 1 + m, CMP); // for a sort of a sort, according to the greedy strategy , a breeder must cat received a [] contiguous stretch sorted, then the time goes back to the task of arranging the 2 
	for (int I =. 1; I <= m; I ++) { 
		S [I] = s [i-1] + a [i]; // s is a prefix a and a 
	} 
	Memset (DP, 63 is, the sizeof (DP)); 
	for (int I = 0; I <= P; I ++) DP [I ] [0] = 0; // initialization 
	for (int i = 1; i <= p; i ++) {// for each time to p times the period of continuous 
		int. 1 = head, tail =. 1; 
		List [. 1] = 0; 
		for (int J =. 1; J <= m; J ++) { 
			DP [I] [J] = min (DP [I-. 1] [J], DP [I-. 1] [List [head]] A + [J] * (J-List [head]) - (S [J] -s [List [head]])); 
			IF (DP [. 1-I] [J] + S [J]> = 455743088879883099 ) continue; 
			the while (head <tail && ((the Y (I-. 1, List [ tail-1]) - Y ( i-1, list [tail])) * (list [tail] -j)> (Y (i-1, list [tail]) - Y (i-1, j)) * (List [tail-1] -list [tail]))) tail--; 
			// compare one by one, until the queue node is not the rest of the time (in fact, a number that would be the rest of us initially placed node 0 to ensure that the situation may be the first one from the start plus the backward elements), 
			// or K1> K2, we end the cycle, and continue to the next element. 
			List [tail ++] = J; 
		} 
	} 
	the printf ( "% LLD \ n-", DP [P] [m]); 
return 0; 
}

  

1610: Toy Packing

 https://www.cnblogs.com/gaojunonly1/p/10409738.html

 

 

Advanced practice // 
// While this approach on a question that is (N ^ 2) could go 
//https://blog.csdn.net/qq_36038511/article/details/82906874 
 // see their own derivation formula See 
#include <cstdio> 
#include <CString> 
#include <algorithm> 
the using namespace STD; 
int List [11000]; 
Long Long F [11000], T [11000], C [11000]; 
int n-, S; 
int X- (I int) 
{ 
	return C [I]; 
} 
int the Y (I int) 
{ 
	return F [I] -S * C [I]; 
} 
Double slop (int J1, J2 int) 
{ 
	return Double (the Y (J2) -Y (J1)) / Double (X-(J2) the -X-(J1)); 
} 
int main () 
{ 
	Scanf ( "% D% D", & n-, & S); 
	for (int I =. 1; I <= n-; I ++) 
	{ 
		Long Long TT, CC;
		scanf("%lld%lld",&tt,&cc);
		t[i]=t[i-1]+tt;
		c[i]=c[i-1]+cc;
	}
	int head=1,tail=1;
	for (int i=1;i<=n;i++)
	{
		while (head+1<=tail&&slop(list[head],list[head+1])<t[i]) head++;
		f[i]=f[list[head]]+(t[i]+S)*(c[i]-c[list[head]])+(c[n]-c[i])*S;
		while (head<=tail-1&&slop(list[tail],i)<slop(list[tail-1],list[tail])) tail--;
		list[++tail]=i;
	}
	printf("%lld\n",f[n]);
	return 0;
}


#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include <SET> 
the using namespace STD; 
const int MAXN = 10010; 
const int = INF 0x3FFFFFFF; 
typedef Long Long LL; 
int n-, S; 
LL TT [MAXN], cost [MAXN]; 
LL DP [MAXN]; 
int que [MAXN]; 
/ * 
set j <k <i, j when k ratio preferably (Ps: C expressed for convenience Cost, T represents Time) 

the dp [k] + S * ( C [n] -C [k]) + T [i] * (C [i] -C [k]) <= dp [j] + S * (C [n] -C [j]) + T [i] * (C [i] -C [j]) 

to the brackets removed dp [k] + S * C [n] -S * C [k] + T [i] * C [i] -T [i] * C [k] <= dp [ j] + S * C [n ] -S * C [j] + T [i] * C [i] -T [i] * C [j] 

erasing grade dp [k] -S * C [ k] - T [i] * C [k ] <= dp [j] -S * C [j] -T [i] * C [j] 

transposing give dp [k] -dp [j] <= (S + T [i]) * (C [ k] -C [j]) condition 1 

then (condition 1) j preferably established ratio k, j or k preferably ratio 

(dp [k] -dp [j ]) / (C [ k] -C [j]) is the slope 
* / 
bool judge (int j, int k , int i) {// j <k <i, k is determined not better (dp [k] -dp [j ]) / (C [k] - C [j]) is the slope 
	int s1 = dp [k] -dp [j];
	int s2=(s+tt[i])*(cost[k]-cost[j]);
	return s1<=s2 ? 1:0;
}
bool judge1(int j,int k,int i){  //j<k<i,
	int s1=(dp[k]-dp[j])*(cost[i]-cost[k]); 
	int s2=(dp[i]-dp[k])*(cost[k]-cost[j]);//交换看看,其实是除法 
	return s1>=s2 ? 1:0;
}
int main(){
	scanf("%d %d",&n,&s);
	for(int i=1;i<=n;i++){
		int t,cc;
		scanf("%d %d",&t,&cc);
		tt[i]=tt[i-1]+t;
		cost[i]=cost[i-1]+cc;
	}
	dp[0]=0;
	que[1]=0;
	int head=1,tail=1;
	for(int i=1;i<=n;i++){
		while(head<tail&&judge(que[head],que[head+1],i)) head++;
		int j=que[head];
		dp[i]=dp[j]+s*(cost[n]-cost[j])+tt[i]*(cost[i]-cost[j]);
		while(head<tail&&judge1(que[tail-1],que[tail],i)) tail--;
		que[++tail]=i;
	}
	printf("%lld\n",dp[n]);
return 0;
}

  

1611: warehouse construction

Like, you can write the equation of violence, and launch step by step

https://www.sogou.com/link?url=hedJjaC291P3yGwc7N55kLSc2ls_Ks2xA8PNccprARSNfcVjEss-9du4r-bJ3iQstsCnpVGpPpA.

Another f [i] = f [j] + Calc (j + 1, i), Calc (j + 1, i) represents the i to j + 1 of all goods shipped to the cost i

For this violence statistics is this:

for(k=j+1;k<=i;k++)
{
  int SS=0;
  SS+=(Dis[i]-Dis[j])*P[j];
}

A set Val [i] = Val [i-1] + P [i] * Dis [i]; and a P_Qzh [i] = P_Qzh [i-1] + P [i];

SS is the Calc (j + 1, i), is easy to find SS = Dis [i] * (P_Qzh [i] -P_Qzh [j]) - (Val [i] -Val [j]);

Then there was the n- 2 violence

Routine optimization of the slope is then used, as follows

j<k<i (若k比j优)
dp[j]+Cost[i]+Dis[i]*(P_Qzh[i]-P_Qzh[j])-(Val[i]-Val[j]) (1)
--->dp[j]+Cost[i]+Dis[i]*P_Qzh[i]-Dis[i]*P_Qzh[j]-Val[i]+Val[j]

dp[k]+Cost[i]+Dis[i]*(P_Qzh[i]-P_Qzh[k])-(Val[i]-Val[k]) (2)
--->dp[k]+Cost[i]+Dis[i]*P_Qzh[i]-Dis[i]*P_Qzh[k]-val[i]+Val[k]

若(1)>=(2)
---> dp[k]-Dis[i]*P_Qzh[k]+Val[k] <= dp[j]-Dis[i]*P_Qzh[j]+Val[j]
---> (dp[k]+Val[k])-(dp[j]+Val[j]) <= Dis[i]*(P_Qzh[k]-P_Qzh[j])

 

#include <the iostream> 
#include <CString> 
#include <the cmath> 
#include <algorithm> 
#include <Stack> 
#include <cstdio> 
#include <Queue> 
#include <Map> 
#include <Vector> 
#include <SET> 
namespace std a using; 
const int MAXN = 1e6 + 10; 
const int INF = 0x3FFFFFFF; 
typedef Long Long LL; 
// write to the state when all of a sudden expression 
// can first try to think of violence, then a step by step break down this expression formula 
int n-; 
LL DIS [MAXN], PP [MAXN], a [MAXN], DP [MAXN]; 
// PP prefix p (the number of goods) and, a is p [i] * dis [i ] prefix and 
int List [MAXN], c [MAXN], P [MAXN]; 
// P is the number, c is constructed amount 
LL X-(I int) { 
	return PP [I]; 
} 
LL the Y (I int) { 
	return DP [I] + A [I];
}


  

1612: Special Operations Team

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1100000;
const int INF=0x3fffffff;
typedef long long LL;
int n,a,b,c;
int list[maxn];
LL dp[maxn],s[maxn];
LL sqr(LL x){
	return x*x;
}
LL X(int i){
	return s[i];
}
LL Y(int i){
	return dp[i]+a*sqr(s[i])-b*s[i];
}
int main(){
	scanf("%d %d %d %d",&n,&a,&b,&c);
	for(int i=1;i<=n;i++){
		scanf("%d",&s[i]);
		s[i]+=s[i-1];
	}
	int head=1,tail=1;
	list[0]=0;
	for(int i=1;i<=n;i++){
		while(head<tail&&(Y(list[head])-Y(list[head+1]))<(2*a*s[i])*(X(list[head])-X(list[head+1]))) head++;
		dp[i]=dp[list[head]]+a*sqr(s[i]-s[list[head]])+b*(s[i]-s[list[head]])+c;
		while(head<tail&&(Y(list[tail-1])-Y(list[tail]))*(X(list[tail])-X(i))<(Y(list[tail])-Y(i))*(X(list[tail-1])-X(list[tail]))) tail--;
		list[++tail]=i;
	}
	printf("%lld",dp[n]);
return 0;
}

  

 

Guess you like

Origin www.cnblogs.com/shirlybaby/p/12656491.html