经典好题!!!区间&背包dp练习题题解(F、G、H、M、N、P、R、S、T、X、U)

F题

There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?

Input
Input contains multiple cases. Each case consists of two lines:
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.

Output
A single line contains one integer representing the answer.

Sample Input
zzzzzfzzzzz
abcdefedcba
abababababab
cdcdcdcdcdcd

Sample Output
6
7

题意

有两个字符串长度相同,现在有一个painter,一次可以把第一个字符串中的一段区间内的所有字母都换成同一个字母(这个字母可以是任意一个),问最少执行多少次操作,才能将第一个字符串转换成第二个字符串

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100 + 10;
char s1[N], s2[N];
int dp[N][N];
int ans[N];
int main()
{
    while (scanf("%s%s", s1, s2) != EOF)
    {
        int len = strlen(s1);
        memset(dp, 0, sizeof(dp));
        for (int j = 0; j < len; j++)
        {
            for (int i = j; i >= 0; i--)
            {
                dp[i][j] = dp[i + 1][j] + 1;
                for (int k = i + 1; k <= j; k++)
                {
                    if (s2[i] == s2[k])
                        dp[i][j] = min(dp[i][j], dp[i + 1][k] + dp[k + 1][j]);
                }
            }
        }
        for (int i = 0; i < len; i++)
            ans[i] = dp[0][i];
        for (int i = 0; i < len; i++)
        {
            if (s1[i] == s2[i])
                ans[i] = ans[i - 1];
            else
            {
                for (int j = 0; j < i; j++)
                    ans[i] = min(ans[i], ans[j] + dp[j + 1][i]);
            }
        }
        printf("%d\n", ans[len - 1]);
    }
    return 0;
}

G题

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

题意:
有T组数据,每组数据有n只野狼,接下来一行有n个数据,代表杀掉这只狼要承受的伤害,接下来一行n数据,与上一行相对应,代表杀掉第i只狼后,会受到这只狼左边和右边的附加伤害,问杀掉所有狼的最小伤害是多少?

思路:dp[i][j] 代表杀死第 [ i , j ]的狼时所承受的最小伤害。a[i]表示第i头狼的初始攻击力,b[i]表示第i头狼对相邻狼的加成值。然后枚举区间,更新区间最小值。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 210
using namespace std;
int a[N], b[N], dp[N][N];
int main()
{
    int t, Case = 1;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++)
            scanf("%d", &b[i]);
        b[0] = b[n + 1] = 0;
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; i++)
            for (int j = i; j <= n; j++)
                dp[i][j] = inf;

        for (int len = 1; len <= n; len++)
        {
            for (int i = 1; i <= n - len + 1; i++)
            {
                int j = i + len - 1;
                for (int k = i; k <= j; k++)
                    dp[i][j] = min(dp[i][j], dp[i][k - 1] + a[k] + dp[k + 1][j] + b[i - 1] + b[j + 1]);
            }
        }
        printf("Case #%d: %d\n", Case++, dp[1][n]);
    }
    return 0;
}

H题

Keeping track of all the cows can be a tricky task so Farmer John has installed a system to automate it. He has installed on each cow an electronic ID tag that the system will read as the cows pass by a scanner. Each ID tag’s contents are currently a single string with length M (1 ≤ M ≤ 2,000) characters drawn from an alphabet of N (1 ≤ N ≤ 26) different symbols (namely, the lower-case roman alphabet).

Cows, being the mischievous creatures they are, sometimes try to spoof the system by walking backwards. While a cow whose ID is “abcba” would read the same no matter which direction the she walks, a cow with the ID “abcb” can potentially register as two different IDs (“abcb” and “bcba”).

FJ would like to change the cows’s ID tags so they read the same no matter which direction the cow walks by. For example, “abcb” can be changed by adding “a” at the end to form “abcba” so that the ID is palindromic (reads the same forwards and backwards). Some other ways to change the ID to be palindromic are include adding the three letters “bcb” to the begining to yield the ID “bcbabcb” or removing the letter “a” to yield the ID “bcb”. One can add or remove characters at any location in the string yielding a string longer or shorter than the original string.

Unfortunately as the ID tags are electronic, each character insertion or deletion has a cost (0 ≤ cost ≤ 10,000) which varies depending on exactly which character value to be added or deleted. Given the content of a cow’s ID tag and the cost of inserting or deleting each of the alphabet’s characters, find the minimum cost to change the ID tag so it satisfies FJ’s requirements. An empty ID tag is considered to satisfy the requirements of reading the same forward and backward. Only letters with associated costs can be added to a string.

Input
Line 1: Two space-separated integers: N and M
Line 2: This line contains exactly M characters which constitute the initial ID string
Lines 3… N+2: Each line contains three space-separated entities: a character of the input alphabet and two integers which are respectively the cost of adding and deleting that character.

Output
Line 1: A single line with a single integer that is the minimum cost to change the given name tag.
Sample Input
3 4
abcb
a 1000 1100
b 350 700
c 200 800
Sample Output
900

Hint
If we insert an “a” on the end to get “abcba”, the cost would be 1000. If we delete the “a” on the beginning to get “bcb”, the cost would be 1100. If we insert “bcb” at the begining of the string, the cost would be 350 + 200 + 350 = 900, which is the minimum.

题意:
给出一个长度为n的字符串,给出m种字母增加和删除花费的代价,求让给出的字符串变成回文串的最小代价。

思路:
增加或者减少最少字母使其变为回文串是一个经典的dp问题,这是一个区间dp问题;
定义dp [ i ] [ j ] 为区间 i 到 j 变成回文的最小代价。
那么对于dp[i][j]三种情况

首先:对于一个串如果s[i]==s[j],那么dp[i][j]=dp[i+1][j-1];

其次:如果dp[i+1][j]是回文串,那么dp[i][j]=dp[i+1][j]+min(add[i],del[i]);

最后,如果dp[i][j-1]是回文串,那么dp[i][j]=dp[i][j-1] + min(add[j],del[j]);

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
using namespace std;
const int N = 2005;
char s[2];
int a[27];
char str[N];
int dp[N][N];

int main()
{
	int n, m;
	scanf("%d %d", &n, &m);
	scanf("%s", str);
	int add, del;
	for (int i = 0; i < n; i++) {
		scanf("%s %d %d", s, &add, &del);
		int pos = s[0] - 'a';
		a[pos] = min(add, del);
	}
	for (int i = m - 1; i >= 0; i--) {
		for (int j = i + 1; j < m; j++) {
			dp[i][j] = min(dp[i][j - 1] + a[str[j] - 'a'], dp[i + 1][j] + a[str[i] - 'a']);
			if (str[i] == str[j])
				dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
		}
	}
	printf("%d\n", dp[0][m - 1]);
	return 0;
}

M题

The cows are trying to become better athletes, so Bessie is running on a track for exactly N (1 ≤ N ≤ 10,000) minutes. During each minute, she can choose to either run or rest for the whole minute.

The ultimate distance Bessie runs, though, depends on her ‘exhaustion factor’, which starts at 0. When she chooses to run in minute i, she will run exactly a distance of Di (1 ≤ Di ≤ 1,000) and her exhaustion factor will increase by 1 – but must never be allowed to exceed M (1 ≤ M ≤ 500). If she chooses to rest, her exhaustion factor will decrease by 1 for each minute she rests. She cannot commence running again until her exhaustion factor reaches 0. At that point, she can choose to run or rest.

At the end of the N minute workout, Bessie’s exaustion factor must be exactly 0, or she will not have enough energy left for the rest of the day.

Find the maximal distance Bessie can run.

Input

  • Line 1: Two space-separated integers: N and M
  • Lines 2…N+1: Line i+1 contains the single integer: Di

Output

  • Line 1: A single integer representing the largest distance Bessie can run while satisfying the conditions.

Sample Input
5 2
5
3
4
2
10
Sample Output
9

题意:
在赛道跑n分钟,每分钟可以选择跑或者休息,以i分钟跑时会跑完Di的距离但疲劳会+1,如果休息,每分钟疲劳会-1,但要减到0才能再次跑。疲劳不会超过m,在n分钟结束后,疲劳必须为0,求最大距离。

思路:

这是一个区间dp题,用f[i][j]表示第i分钟疲劳值为j时的最大值,由于每分钟有休息或者跑两种状态,分别考虑跑和休息时的状态转移方程。

当选择跑时,当前分钟的最大值由上一分钟的最大值决定,有:f[i][j]=f[i-1][j-1]+D[i]
当选择休息时有:当前状态的最大值由前面决定开始休息的时间点i-j决定,故有:f[i][0]=max{ d[i-j][j] },j<=m

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e4+5;
int dp[N][505], n, m, a[N];
int main()
{
	int i, j;  
	while (cin>>n>>m)
	{
		for (i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		memset(dp, 0, sizeof(dp));
		for (i = 1; i <= n; i++)
		{
			for (j = 1; j <= m; j++)
				dp[i][j] = dp[i - 1][j - 1] + a[i];
			dp[i][0] = dp[i - 1][0];
			for (int k = 1; k <= m && i >= k; k++)
				dp[i][0] = max(dp[i][0], dp[i - k][k]);
		}
		printf("%d\n", dp[n][0]);
	}
	return 0;
}

N题

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。

Input
多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。

Output
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。

Sample Input
1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0
Sample Output
-45
32

题意很明显,这里就不再赘述,直接说思路吧

思路:
其实一开始想的是用贪心,然后发现应该是01背包。
将该问题转化成0-1背包问题,由于每个菜只能购买一次,而且每次买菜的时候饭卡余额 m 要大于等于5,因此先利用0-1背包算出 m - 5 的钱最多能买多少菜,然后拿最后的5块钱买最贵的菜,才能使饭卡余额达到最少。还要注意在进行0-1背包之前要将所有的菜从小到大排一下序就可

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 1100;
int p[MAXN], dp[MAXN];
int main() 
{
	int n, m;
	while (cin >> n && n) 
	{
		
		for (int i = 0; i < n; i++) 
			cin >> p[i];
		cin >> m;
		if (m < 5) 
		{
			cout << m << endl;
			continue;
		}
		sort(p, p + n);
		memset(dp, 0, sizeof(dp));
		for (int i = 0; i < n - 1; i++)
			for (int j = m - 5; j >= p[i]; j--)
				dp[j] = max(dp[j], dp[j - p[i]] + p[i]);
		cout << m - dp[m - 5] - p[n - 1] << endl;
	}
	return 0;
}

P题

Battle Ships is a new game which is similar to Star Craft. In this game, the enemy builds a defense tower, which has L longevity. The player has a military factory, which can produce N kinds of battle ships. The factory takes ti seconds to produce the i-th battle ship and this battle ship can make the tower loss li longevity every second when it has been produced. If the longevity of the tower lower than or equal to 0, the player wins. Notice that at each time, the factory can choose only one kind of battle ships to produce or do nothing. And producing more than one battle ships of the same kind is acceptable.

Your job is to find out the minimum time the player should spend to win the game.

Input
There are multiple test cases.
The first line of each case contains two integers N(1 ≤ N ≤ 30) and L(1 ≤ L ≤ 330), N is the number of the kinds of Battle Ships, L is the longevity of the Defense Tower. Then the following N lines, each line contains two integers t i(1 ≤ t i ≤ 20) and li(1 ≤ li ≤ 330) indicating the produce time and the lethality of the i-th kind Battle Ships.

Output
Output one line for each test case. An integer indicating the minimum time the player should spend to win the game.

Sample Input
1 1
1 1
2 10
1 1
2 5
3 100
1 10
3 20
10 100

Sample Output
2
4
5

题意:
有一座血量为L的塔,现在要造一些军舰去推塔,给出n种能造的军舰。军舰的杀伤力不同,给出的杀伤力代表建造完成后一秒钟军舰能造成的伤害,同时造这些军舰花费的时间也是不同的,造军舰的种类与数量不受限制。求推塔完成的最短时间。
思路:
这是一个完全背包问题,塔的血量可以看做背包容量,造军舰花费时长代表物品大小,军舰杀伤力代表物品的价值,又因为军舰种类数目不受限制,所以视为完全背包问题。
我们用dp[i]表示i时间的破坏值
状态转移方程为:dp[j]=max(dp[j],dp[j-t[i]]+(j-t[i])*l[i]);

代码如下:

#include <iostream>
#include <algorithm>
#include<cstring>
using namespace std;
int n, l;
int t[40], tt[40];
int dp[300];
int main()
{
    while (scanf("%d %d", &n, &l) != EOF)
    {
        for (int i = 0; i < n; i++)
        {
            scanf("%d %d", &t[i], &tt[i]);
        }
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; i++)
        {
            for (int j = t[i]; j < 300; j++)
            {
                dp[j] = max(dp[j], dp[j - t[i]] + (j - t[i]) * tt[i]);
                if (dp[j] >= l)
                    break;
            }
        }
        for (int i = 0; i < 300; i++)
        {
            if (dp[i] >= l)
            {
                cout << i << endl;
                break;
            }
        }
    }
    return 0;
}

R题

The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before retiring to a comfortable job at a university.

For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible.

His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.

Input
The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line j gives an integer Mj and a floating point number Pj .
Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .
Output
For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set.

Notes and Constraints
0 < T <= 100
0.0 <= P <= 1.0
0 < N <= 100
0 < Mj <= 100
0.0 <= Pj <= 1.0
A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.

Sample Input
3
0.04 3
1 0.02
2 0.03
3 0.05
0.06 3
2 0.03
2 0.03
3 0.05
0.10 3
1 0.03
2 0.02
3 0.05
Sample Output
2
4
6

题意:
有一个人想要抢劫银行,每家银行都具有一定的金额和被抓到的概率,知道他被抓的最大概率,求他在被抓的情况下,抢劫最多能有多少金额。

思路:
被抓概率可以转换成安全的概率,他的安全概率在大于1-P时都是安全的。就是一个01背包的变种。抢劫的金额为0时,肯定是安全的,所以d[0]=1,其他金额初始为最危险的所以概率全为0。

代码:

#include<iostream> 
#include<cstring>  
#include<algorithm>
using namespace std;
double q[105], f[10005];
int main()
{
    int t, n, i, j, k, M, m[105];
    double p;
    scanf("%d", &t);
    while (t--)
    {
        M = 0;
        memset(f, 0, sizeof(f));
        scanf("%lf %d", &p, &n);
        for (i = 1; i <= n; i++)
        {
            cin >> m[i] >> q[i];
            M = M + m[i];
        }
        f[0] = 1;
        for (i = 1; i <= n; i++)
        {
            for (j = M; j >= m[i]; j--)
                f[j] = max(f[j], f[j - m[i]] * (1 - q[i])); //背包 
        }
        for (i = M; i >= 0; i--)
        {
            if (f[i] >= 1 - p)
            {
                printf("%d\n", i);
                break;
            }
        }
    }
}

S题

Recently, iSea went to an ancient country. For such a long time, it was the most wealthy and powerful kingdom in the world. As a result, the people in this country are still very proud even if their nation hasn’t been so wealthy any more.
The merchants were the most typical, each of them only sold exactly one item, the price was Pi, but they would refuse to make a trade with you if your money were less than Qi, and iSea evaluated every item a value Vi.
If he had M units of money, what’s the maximum value iSea could get?

Input
There are several test cases in the input.

Each test case begin with two integers N, M (1 ≤ N ≤ 500, 1 ≤ M ≤ 5000), indicating the items’ number and the initial money.
Then N lines follow, each line contains three numbers Pi, Qi and Vi (1 ≤ Pi ≤ Qi ≤ 100, 1 ≤ Vi ≤ 1000), their meaning is in the description.

The input terminates by end of file marker.

Output
For each test case, output one integer, indicating maximum value iSea could get.

Sample Input
2 10
10 15 10
5 10 5
3 10
5 10 5
3 5 6
2 7 3
Sample Output
5
11

题意:
m数量的钱 ,去买东西, 共有 n 件物品,每件物品有价格 P、价值 V、 属性 Q, 属性Q 是指如果想买这件物品你的手中的钱的数量不低于Q 。但是实际上买这样东西只需要花费价格P。问给你钱M ,列出N件物品,最多能获得多少价值的东西?

思路:
首先考虑,如果在价格一样,价值一样但属性不一样的情况下,先选哪一种?
一定是先考虑属性Q大的物品!!!而价格一样,属性大,那么Q-P的值就大。
因此,在进行01背包选择之前,需要对物品按照Q-P从小到大排序(因为01背包物品选择需要逆序)

#include<iostream>
#include<algorithm>
using namespace std;
struct node {
    int p, q, v, c;
}s[5005];
int dp[5005];

int cmp(node a, node b)
{
    return a.q - a.p < b.q - b.p;
}

int main()
{
    int n, m;
    while (cin >> n >> m)
    {
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; i++)
            cin >> s[i].p >> s[i].q >> s[i].v;
        sort(s, s + n, cmp);
        for (int i = 0; i < n; i++)
            for (int j = m; j >= s[i].q; j--)
                dp[j] = max(dp[j], dp[j - s[i].p] + s[i].v);
        cout << dp[m] << endl;
    }
    return 0;
}

T题

Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversibly Bound Money (IBM). The idea behind is simple. Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank. You know that this process is irreversible, the coins cannot be removed without breaking the pig. After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid.

But there is a big problem with piggy-banks. It is not possible to determine how much money is inside. So we might break the pig into pieces only to find out that there is not enough money. Clearly, we want to avoid this unpleasant situation. The only possibility is to weigh the piggy-bank and try to guess how many coins are inside. Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. Then there is some minimum amount of money in the piggy-bank that we can guarantee. Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank. We need your help. No more prematurely broken pigs!
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers E and F. They indicate the weight of an empty pig and of the pig filled with coins. Both weights are given in grams. No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000. On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each specifying one coin type. These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000). P is the value of the coin in monetary units, W is it’s weight in grams.
Output
Print exactly one line of output for each test case. The line must contain the sentence “The minimum amount of money in the piggy-bank is X.” where X is the minimum amount of money that can be achieved using coins with the given total weight. If the weight cannot be reached exactly, print a line “This is impossible.”.

Sample Input
3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4
Sample Output
The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible.

题意:
给出小猪钱罐的重量和装满钱后的重量,然后是几组数据,每组数据包括每种钱币的价值与重量,要求出重量最少能装满钱罐时的最大价值

思路:
就是一个简单的完全背包…
直接贴代码啦

#include <iostream>
#include <cstdio>
#include <cstring>
#include<algorithm>
using namespace std;
const int MAX_N = 1000003;
int v[MAX_N], w[MAX_N], dp[MAX_N];
int main() 
{
    int cases, E, F, N, i, j, W;
    cin >> cases;
    while (cases--) {
        cin >> E >> F;
        cin >> N;
        W = F - E;
        memset(v, 0, sizeof(v));
        memset(w, 0, sizeof(w));
        for (i = 1; i <= W; i++) {
            dp[i] = MAX_N;

        }
        dp[0] = 0;
        for (i = 1; i <= N; i++) {
            cin >> v[i] >> w[i];
        }

        for (i = 1; i <= N; i++)
            for (j = w[i]; j <= W; j++) {
                dp[j] = min(dp[j], dp[j - w[i]] + v[i]);
            }
        if (dp[W] != MAX_N) {

            cout << "The minimum amount of money in the piggy-bank is " << dp[W] << "." << endl;
        }
        else {
            cout << "This is impossible." << endl;
        }

    }
    return 0;
}

X题

When the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends and families as gifts, but also can the souvenirs leave them good recollections. All in all, the prices of souvenirs are not very dear, and the souvenirs are also very lovable and interesting. But the money the people have is under the control. They can’t buy a lot, but only a few. So after they admire all the souvenirs, they decide to buy some ones, and they have many combinations to select, but there are no two ones with the same kind in any combination. Now there is a blank written by the names and prices of the souvenirs, as a top coder all around the world, you should calculate how many selections you have, and any selection owns the most kinds of different souvenirs. For instance:

And you have only 7 RMB, this time you can select any combination with 3 kinds of souvenirs at most, so the selections of 3 kinds of souvenirs are ABC (6), ABD (7). But if you have 8 RMB, the selections with the most kinds of souvenirs are ABC (6), ABD (7), ACD (8), and if you have 10 RMB, there is only one selection with the most kinds of souvenirs to you: ABCD (10).

Input
For the first line, there is a T means the number cases, then T cases follow.
In each case, in the first line there are two integer n and m, n is the number of the souvenirs and m is the money you have. The second line contains n integers; each integer describes a kind of souvenir.
All the numbers and results are in the range of 32-signed integer, and 0<=m<=500, 0<n<=30, t<=500, and the prices are all positive integers. There is a blank line between two cases.

Output
If you can buy some souvenirs, you should print the result with the same formation as “You have S selection(s) to buy with K kind(s) of souvenirs”, where the K means the most kinds of souvenirs you can buy, and S means the numbers of the combinations you can buy with the K kinds of souvenirs combination. But sometimes you can buy nothing, so you must print the result “Sorry, you can’t buy anything.”
Sample Input
2
4 7
1 2 3 4

4 0
1 2 3 4
Sample Output
You have 2 selection(s) to buy with 3 kind(s) of souvenirs.
Sorry, you can’t buy anything.

思路:
二维0/1背包
题目给定n个物品的价钱和m的钱,问最多能买到的物品数有几种方案。

  • 很明显就可以写出状态转移方程dp[i][j][k]表示的是前i个物品选j个总价钱为k的方案数
  • 那么dp[i][j][k] = dp[i-1][j][k]+dp[i-1][j-1][k-v[i]]。由于都可以把第一维去掉,所以正常的情况下直接写出dp[j][k] = dp[j][k] + dp[j-1][k-v[i]]

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int inf = 0x3f3f3f3f;
using namespace std;
int main()
{
	int i, j, k, t, n, m, Min, ans, sum, v[35], dp[505][35];
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &m);
		Min = inf; sum = 0;
		for (i = 0; i < n; i++)
			scanf("%d", v + i), Min = min(v[i], Min), sum += v[i];
		if (Min > m)
		{
			printf("Sorry, you can't buy anything.\n");
			continue;
		}
		if (sum <= m)
		{
			printf("You have 1 selection(s) to buy with %d kind(s) of souvenirs.\n", n);
			continue;
		}
		sort(v, v + n);
		sum = 0;
		for (i = 0; i < n; i++)
		{
			sum += v[i];
			if (sum > m)
			{
				ans = i;
				break;
			}
		}
		memset(dp, 0, sizeof(dp));
		for (i = 0; i < m; i++)
			dp[i][0] = 1;
		for (i = 0; i < n; i++)
			for (j = m; j >= v[i]; j--)
				for (k = ans; k >= 0; k--)
					dp[j][k] += dp[j - v[i]][k - 1];
		printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n", dp[m][ans], ans);
	}
	return 0;
}

U题

Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don’t know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).

Input
Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 – the total number of different facilities). The next N lines contain an integer V (0<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.

Output
For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.
Sample Input
2
10 1
20 1
3
10 1
20 2
30 1
-1
Sample Output
20 10
40 40

题意:
有很多个人,其中每个人有一个自己的权值,权值一共有n种,要分配成两个部分,要尽量保证每个部分的分数尽量接近,并且第一部分的权值要大于等于第二个部分。
思路:
01背包。首先计算总权值sum,以总权值的一半作为背包的容量,由于第二部分的分数恒小于等于总权值一半,把第二部分当作背包模型。又要保证两部分权值要尽量相等,所以把每个人的权值即当做放入背包中的物体的体积,也当做物体的价值,就可以保证第二部分的权值小于第一部分却有尽可能接近第一部分的权值。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 250000+10;
int m[1005], n[1005];
int dp[N];
int main()
{
    int a, b, c, d, e, f;
    while (cin >> a)
    {
        if (a < 0)
            break;
        f = 0;
        memset(dp, 0, sizeof(dp));
        for (b = 0; b < a; b++)
        {
            scanf("%d %d", &m[b], &n[b]);
            f = f + m[b] * n[b];
        }
        e = f / 2;
        for (b = 0; b < a; b++)
        {
            for (c = 0; c < n[b]; c++)
            {
                for (d = e; d >= m[b]; d--)
                {
                    dp[d] = max(dp[d], dp[d - m[b]] + m[b]);
                }
            }
        }
        printf("%d %d\n", f - dp[e], dp[e]);
    }
    return 0;
}

以上就是这周做的dp的练习题,都是区间dp和背包的题目,本人水平有限,如有错误,请da lao指正
留个赞呗~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值