1. 程式人生 > 實用技巧 >Eat Walnuts(區間DP)

Eat Walnuts(區間DP)

題目連線:https://ac.nowcoder.com/acm/contest/8688/E
CSDN食用連結:https://blog.csdn.net/qq_43906000/article/details/109407374

As we all know, in the ACM ICPC held in 2017, the organizer of Xinjiang University presented a box of walnuts to each coach. Our coach is happy to share with the team members except Mr.Watermelon. He is going to test Mr.Watermelon with a game when Mr.Watermelon want to eat some walnuts.

He put some walnuts in a row and let Mr.Watermelon pick one of them. And this walnut is not the first or last in the queue. The price Mr.Watermelon need to pay is : the walnut, the walnut in front of the walnut, and the walnut behind the walnut , the square of the sum of the size of these three walnuts.

For example, now there is a row of walnuts in front of Mr.Watermelon. Their size is: 3 1 50 20 15. If this time Mr.Watermelon picked the third walnut. He needs to pay (1 + 50 + 20) ∗ (1 + 50 + 20) = 5041.

After a walnut is taken away, it will leave the queue. Then Mr.Watermelon picks a walnut again until only two walnuts remain in the queue.

Mr.Watermelon wants to know what the minimum price he will pay when he takes walnuts until there are only two walnuts in the queue. But he needs more time to spend with his girlfriend. So he ask you to help him calculate this problem.

輸入描述:

Input contains multiple test cases.The first line of each test case contains a integer n(3 ≤ n ≤ 100), the number of walnuts at the beginning. The second line contains n positive integers separated by spaces, representing the size of each walnut. Each positive integer does not exceed 1,000.

For 50% of the testcases, n ≤ 50.

For 90% of the testcases, n ≤ 90.

For 100% of the testcases, n ≤ 100.

The number of the testcases does not exceed 1000.

輸出描述:

For each test case, print a integer–the minimum price Mr.Watermelon will pay.

示例1
輸入
5
3 1 50 20 15

輸出
6698

題目大意:給你n件商品,你不能夠買第一件和最後一件,而你買第i個商品的代價是\((a_i+a_{i+1}+a_{i-1})^2\),問最後買光所有商品的最小代價是多少

emmm,本來可以一發AC的。。。結果inf開小了QAQ。一看這玩意兒就知道是個區間DP,那麼於是三連for上頭,列舉長度,列舉起點,列舉終點,由於第一件和最後一件不能買,所以有:

for (int len=2; len<=n-2; len++){//由於2個買不了,所以長度只有n-2
	for (int st=2; st+len-1<=n-1; st++){//對2-n-1進行區間DP
		int ed=st+len-1; 
		for (int k=st; k<=ed; k++){
			.....
		}
	}
}

那麼DP的轉移方程怎麼寫呢,其實之前部落格裡面有一題殺狼的題目也是相同的道理https://www.cnblogs.com/lonely-wind-/p/13264259.html
我們列舉中間的保留點,那麼就可以得到其方程:
\(dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+(a[k]+a[i-1]+a[j+1])^2)\)

#include <bits/stdc++.h>
using namespace std;

const int mac=120;
const int inf=5e8+10;

int a[mac],dp[mac][mac];

int pw(int x){return x*x;}

int main(int argc, char const *argv[])
{
	int n;
	while (~scanf ("%d",&n)){
		for (int i=1; i<=n; i++)
			scanf ("%d",&a[i]);
		for (int i=1; i<=n; i++)
			for (int j=i; j<=n; j++)
				dp[i][j]=inf;
		for (int i=2; i<n; i++) dp[i][i]=pw(a[i]+a[i-1]+a[i+1]);
		for (int len=2; len<=n-2; len++){
			for (int st=2; st+len-1<=n-1; st++){
				int ed=st+len-1; 
				for (int k=st; k<=ed; k++){
					dp[st][ed]=min(dp[st][ed],dp[st][k-1]+dp[k+1][ed]+pw(a[k]+a[st-1]+a[ed+1]));
				}
			}
		}
		printf ("%d\n",dp[2][n-1]);
	}
	return 0;
}