区间DP

HDU - 5115

Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not all, Dire Wolves appear to originate from Draenor.
Dire wolves look like normal wolves, but these creatures are of nearly twice the size. These powerful beasts, 8 - 9 feet long and weighing 600 - 800 pounds, are the most well-known orc mounts. As tall as a man, these great wolves have long tusked jaws that look like they could snap an iron bar. They have burning red eyes. Dire wolves are mottled gray or black in color. Dire wolves thrive in the northern regions of Kalimdor and in Mulgore.
Dire wolves are efficient pack hunters that kill anything they catch. They prefer to attack in packs, surrounding and flanking a foe when they can.
— Wowpedia, Your wiki guide to the World of Warcra

Matt, an adventurer from the Eastern Kingdoms, meets a pack of dire wolves. There are N wolves standing in a row (numbered with 1 to N from left to right). Matt has to defeat all of them to survive.

Once Matt defeats a dire wolf, he will take some damage which is equal to the wolf’s current attack. As gregarious beasts, each dire wolf i can increase its adjacent wolves’ attack by b i. Thus, each dire wolf i’s current attack consists of two parts, its basic attack ai and the extra attack provided by the current adjacent wolves. The increase of attack is temporary. Once a wolf is defeated, its adjacent wolves will no longer get extra attack from it. However, these two wolves (if exist) will become adjacent to each other now.

For example, suppose there are 3 dire wolves standing in a row, whose basic attacks ai are (3, 5, 7), respectively. The extra attacks b i they can provide are (8, 2, 0). Thus, the current attacks of them are (5, 13, 9). If Matt defeats the second wolf first, he will get 13 points of damage and the alive wolves’ current attacks become (3, 15).

As an alert and resourceful adventurer, Matt can decide the order of the dire wolves he defeats. Therefore, he wants to know the least damage he has to take to defeat all the wolves.

Input

The first line contains only one integer T , which indicates the number of test cases. For each test case, the first line contains only one integer N (2 ≤ N ≤ 200).

The second line contains N integers a i (0 ≤ a i ≤ 100000), denoting the basic attack of each dire wolf.

The third line contains N integers b i (0 ≤ b i ≤ 50000), denoting the extra attack each dire wolf can provide.

Output

For each test case, output a single line “Case #x: y”, where x is the case number (starting from 1), y is the least damage Matt needs to take.

Sample Input

2
3
3 5 7
8 2 0
10
1 3 5 7 9 2 4 6 8 10
9 4 1 2 1 2 1 4 5 1

Sample Output

Case #1: 17
Case #2: 74  

Hint

In the first sample, Matt defeats the dire wolves from left to right. He takes 5 + 5 + 7 = 17 points of damage which is the least damage he has to take.
        
 

题意:有一排狼,每只狼有一个伤害A,还有一个伤害B。杀死一只狼的时候,会受到这只狼的伤害A和这只狼两边的狼的伤害B的和。如果某位置的狼被杀,那么杀它左边的狼时就会收到来自右边狼的B,因为这两只狼是相邻的了。求杀掉一排狼的最小代价。

样例解释:

n   = 3

A[] = 3 5 7

B[] = 8 2 0

一共有3只狼,第一次杀掉第一只狼,代价为A[1]+B[2] = 3+2 = 5 (B和A相邻),只剩下第二只狼和第三只狼了,

所以杀掉第二只狼的代价为A[2]+B[3] = 5+0 = 5; 最后剩下一只狼了,代价为A[3] = 7,总代价为5+5+7 = 17;

 

 

解法:设dp[i][j]为消灭编号从i到j只狼的代价,那么结果就是dp[1][n]

    枚举k作为最后一只被杀死的狼,此时会受到a[k]和b[i-1] b[j+1]的伤害 取最小的即可

 

可列出转移方程:dp[i][j]=min(dp[i][j], dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1])

        dp[i][i]=a[i]+b[i-1]+b[j+1];

这里的转移方程理解一下,是表示枚举从i到 j的最后一只被杀掉的狼,这只狼的代价应该是a[k]+b[i-1]+b[j+1]。再加上其余的代价,是f[i][k-1]和f[k+1][j]。

区间DP的枚举方法:先枚举区间长度,再枚举区间左端点,然后枚举状态转移位置。

#include <iostream>
#include <string.h>
using namespace std;
const int INF=1e9+10;
int a[205], b[205], f[205][205];

int main()
{

	int t,n;
	cin>>t;
	for (int u = 1; u <= t; u++)
	{
		cin>>n;
		a[0]=0; b[0]=0;
		a[n+1]=0; b[n+1]=0;
		for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
		for (int i = 1; i <= n; i++) scanf("%d", &b[i]);

		memset(f, 0, sizeof(f));
			for (int i = 1; i <= n; i++)
				for (int j = i; j <= n ; j++)
				{
					f[i][j]=INF;
				}
		
		for (int i = 1; i <= n; i++)
		{
			f[i][i]=a[i]+b[i-1]+b[i+1];
			// f[0][i]=0;
			// f[i][n+1]=0;
		}

		for (int p=1; p <= n; p++)  
			for (int i = 1; i+p<=n; i++) 
			{
			    int j=i+p;
			    for (int k=i; k<=j; k++)
			    {
        	                if (f[i][j]>f[i][k-1]+f[k+1][j]+b[i-1]+b[j+1]+a[k])
				{
			       	    f[i][j]=f[i][k-1]+f[k+1][j]+b[i-1]+b[j+1]+a[k];
				}
			    }
			}
			cout<<"Case #"<<u<<": "<<f[1][n]<<endl;
	}

	return 0;
}

Halloween Costumes LightOJ - 1422

Gappu has a very busy weekend ahead of him. Because, next weekend is Halloween, and he is planning to attend as many parties as he can. Since it's Halloween, these parties are all costume parties, Gappu always selects his costumes in such a way that it blends with his friends, that is, when he is attending the party, arranged by his comic-book-fan friends, he will go with the costume of Superman, but when the party is arranged contest-buddies, he would go with the costume of 'Chinese Postman'.

Since he is going to attend a number of parties on the Halloween night, and wear costumes accordingly, he will be changing his costumes a number of times. So, to make things a little easier, he may put on costumes one over another (that is he may wear the uniform for the postman, over the superman costume). Before each party he can take off some of the costumes, or wear a new one. That is, if he is wearing the Postman uniform over the Superman costume, and wants to go to a party in Superman costume, he can take off the Postman uniform, or he can wear a new Superman uniform. But, keep in mind that, Gappu doesn't like to wear dresses without cleaning them first, so, after taking off the Postman uniform, he cannot use that again in the Halloween night, if he needs the Postman costume again, he will have to use a new one. He can take off any number of costumes, and if he takes off k of the costumes, that will be the last k ones (e.g. if he wears costume A before costume B, to take off A, first he has to remove B).

Given the parties and the costumes, find the minimum number of costumes Gappu will need in the Halloween night.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing an integer N (1 ≤ N ≤ 100) denoting the number of parties. Next line contains N integers, where the ith integer ci (1 ≤ ci ≤ 100) denotes the costume he will be wearing in party i. He will attend party 1 first, then party 2, and so on.

Output

For each case, print the case number and the minimum number of required costumes.

Sample Input

2

4

1 2 1 2

7

1 2 1 1 3 2 1

Sample Output

Case 1: 3

Case 2: 4

有n次聚会,每次聚会需要一件衣服。可以将不同的衣服一起穿在身上,需要时将外面的衣服脱掉。但一件衣服被脱掉之后再次穿上就需要再次计数。

dp[i][j]表示从第i次聚会到第j次聚会需要的衣服数目。

最差的情况是每次聚会都需要一件新衣服,d[i][i]=1

然后考虑一下i和j的衣服如果是相同的,那么d[i][j]=d[i][j-1](直接把i的衣服放在最里面)。

然后再考虑如果i和中间点k的衣服是相同的,那么d[i][j]=min(d[i][j], d[i][k]+d[k+1][j])(枚举中间点k,这个k的衣服就是i的衣服)。

代码:

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

int a[1100];
int dp[1100][1100];
int main(){
	int n,_;
	cin>>_;
	int u=0;
	while (_--){
		cin>>n;
		for (int i=0; i<n; i++) cin>>a[i];
		memset(dp,0x3f,sizeof(dp));
		for (int i=0; i<n; i++) dp[i][i]=1;
		for (int i=2; i<=n; i++){
			for (int j=0; j<n; j++){
				if (a[j]==a[i+j-1])
					dp[j][i+j-1]=min(dp[j][i+j-1],dp[j][i+j-2]);
				for (int k=j; k<j+i-1; k++){
					if (a[j]==a[k])
						dp[j][j+i-1]=min(dp[j][j+i-1],dp[j][k]+dp[k+1][j+i-1]);
				}
			}
		}
		// for (int i=0; i<n; i++) cout<<dp[i][i+1]<<' ';
		printf("Case %d: %d\n",++u,dp[0][n-1]);
	}

	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值