HDU3506-Monkey Party(区间DP+四边形优化)

Far away from our world, there is a banana forest. And many lovely monkeys live there. One day, SDH(Song Da Hou), who is the king of banana forest, decides to hold a big party to celebrate Crazy Bananas Day. But the little monkeys don’t know each other, so as the king, SDH must do something.
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.
Input
There is several test cases. In each case, the first line is n(1 ≤ n ≤ 1000), which is the number of monkeys. The next line contains n positive integers(less than 1000), means the making friends time(in order, the first one and the last one are neighbors). The input is end of file.
Output
For each case, you should print a line giving the mininal time SDH needs on introducing.
Sample Input
8
5 2 4 7 6 1 3 9
Sample Output
105

分析:

题意:
第一次看题目没有懂他到底讲个啥!网上查了才知道就是石子合并!有n只猴坐成一圈,他们要互相介绍他们自己以及自己认识的猴子,他们各自介绍自己所花的时间为给出的数列,猴子每次只能跟自己相邻的猴子之一做介绍,经过介绍,相邻的猴子就默认认识了邻居猴子以及他认识的猴子们,最开始每只猴子只知道自己!问让所有的猴子都互相认识所花费的时间是多少?

解析:
区间DP的经典的算法之一:
我们用dp[i][j]表示第i只猴子到第j只猴子全部互相认识所花费的最少时间,那么:dp[i][j]=dp[i][k]+dp[k+1][j];这样我们就将大问题划分为两个小的子问题。于是我们按照这个方法写出了代码:

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2005
#define INF 0x3f3f3f3f

using namespace std;

int dp[N][N];
int sum[N];
int book[N];

int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		sum[0]=0;
		memset(dp,INF,sizeof(dp));
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&book[i]);
			book[i+n]=book[i];
		}
		for(int i=1;i<=n<<1;i++)
		{
			sum[i]=sum[i-1]+book[i];
			dp[i][i]=0;
		}
		for(int len=1;len<=n;len++)
		{
			for(int i=1;len+i-1<=n<<1;i++)
			{
				int j=len+i-1;
				for(int k=i;k<=j;k++)
				{
					dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
				}
			}
		}
		int Min=INF;
		for(int i=1;i<=n;i++)
		{
			Min=min(Min,dp[i][n+i-1]);
		}
		printf("%d\n",Min);
	}
	return 0;
}

坑爹啊!超时了,没有办法了,怎么办?上网查啊!

四边形优化?这是个什么玩意儿?不懂就学呗:大佬讲的很详细

根据这个四边形优化,我们修修改改,然后又写出了代码:

代码(四边形优化):

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2005
#define INF 0x3f3f3f3f

using namespace std;

int dp[N][N],mark[N][N];
int sum[N];
int book[N];

int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		sum[0]=0;
		memset(dp,INF,sizeof(dp));
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&book[i]);
			book[i+n]=book[i];
		}
		for(int i=1;i<=n<<1;i++)
		{
			sum[i]=sum[i-1]+book[i];
			dp[i][i]=0;
			mark[i][i]=i;
		}
		for(int len=1;len<=n;len++)
		{
			for(int i=1;len+i-1<=n<<1;i++)
			{
				int j=len+i-1;
				for(int k=mark[i][j-1];k<=mark[i+1][j];k++)
				{
					if(dp[i][j]>dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
					{
						dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
						mark[i][j]=k;
					}
				}
			}
		}
		int Min=INF;
		for(int i=1;i<=n;i++)
		{
			Min=min(Min,dp[i][n+i-1]);
		}
		printf("%d\n",Min);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值