【决策单调性分治优化/四边形不等式优化】监狱警卫

前言

模板一套就AC了...

题目

guardians.cpp 1S/128M

你负责将监狱的警卫指派到最疯狂的罪犯所在的监狱。 一共有N间牢房排列成一行,编号从1~N。 第i间牢房恰好容纳了一个疯狂程度为C[i]的罪犯。

每个罪犯都应该有一个警卫监视他/她。 理想情况下,应该让一名警卫监视一个罪犯。 然而,由于预算限制,你只能分配G个警卫。 为了最大程度地降低有人逃脱的总风险,你必须指定每个警卫应该监视哪些罪犯。当然,你应该将每个警卫分配给一组相邻的牢房。
第i个罪犯可能逃脱的风险R[i]由下式给出:
R[i] = C[i] * 指派监视他的警卫监视的罪犯数量
请你分配一个最佳的方案,使所有罪犯的风险之和最小。

输入
第1行:2个整数N和G (1 <= N <= 8000, 1 <= G <= 800)
第2行:N个整数,表示C[i] ( 1 <= C[i] <= 10^9)

输出
第1行:1个整数,表示答案

Sample Input
6 3
11
11
11
24
26
100

Sample Output
299

Explain
第1个警卫监视1~3,第2个警卫监视4~5,第3个警卫监视6

分析

详细的关于该优化的讲解我有写博客:决策单调性分治优化

经观察可以发现本题基本模型为:分组+花费最小

可以写出DP定义与转移方程:

dp[ i ][ j ]:1~j个犯人被第i个狱长监管

对于最后一个狱长i,假设从第k到j的犯人被最后第i狱长监管

dp[ i ][ j ]=min( dp[ i ][ j ],dp[ i-1 ][ k-1 ]+( s[ j ] - s[ k ] ) * ( j - k + 1 ) ) ;                                                                                                   

s[ i ]:1~i的前缀和

初始化:dp[ 1 ][ 1~n ]=INF

然后直接套用【决策单调性分治优化】或【四边形不等式优化】即可,详见代码

决策单调性分治优化-代码(含暴力DP)

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=8000,MAXG=800;
#define INF (1LL << 60) 
ll c[MAXN+5],s[MAXN+5],dp[MAXG+5][MAXN+5];
ll n,g;
void DP(ll d,ll i,ll j,ll optl,ll optr)//决策优化 
{
	if(i>j)
		return ;
	ll mid=(i+j)/2;
	ll opt=INF,id;
	//暴力计算二分点的dp值opt与最小决策点id 
	for(int k=optl;k<=min(mid,optr);k++)
	{
		ll cur=dp[d-1][k-1]+(mid-k+1)*(s[mid]-s[k-1]);
		if(cur

四边形不等式优化-代码

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=8000,MAXG=800;
#define INF (1LL<<60) 
ll c[MAXN+5],s[MAXN+5],dp[MAXG+5][MAXN+5];
ll n,g;
void Solve()
{
	for(int i=0;i<=g;i++)
		for(int j=0;j<=n;j++)
			dp[i][j]=INF;
	dp[0][0]=0;
	for(int i=1;i<=g;i++)
	{
		ll opt=0;
		for(int j=i;j<=n;j++)
			for(int k=opt;k<=j;k++)
			{
				ll tmp=1ll*(j-k+1)*(s[j]-s[k-1]);
				if(dp[i-1][k-1]+tmp<=dp[i][j])
					dp[i][j]=dp[i-1][k-1]+tmp,opt=k;
			}
	}
	/*打表验证单调性 
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j++)
		{
			w[i][j]=(j-i+1)*(s[j]-s[i-1]);
			//printf("%d %d %lld\n",i,j,w[i][j]);
		}
	for(int a=1;a<=n;a++)
		for(int b=a+1;b<=n;b++)
			for(int c=b+1;c<=n;c++)
				for(int d=c+1;d<=n;d++)
					printf("%d %d %d %d %lld %lld\n",a,b,c,d,w[a][c]+w[b][d],w[a][d]+w[b][c]);
	*/
	printf("%lld\n",dp[g][n]);
}
int main()
{
	scanf("%lld%lld",&n,&g);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&c[i]);
		s[i]=s[i-1]+c[i];
	}
	Solve();
	return 0;
}

 

你可能感兴趣的:(决策单调性分治优化,动态规划,四边形不等式优化)