2019 GDUT Winter Training II (背包/基础DP/LIS/LCS/概率DP) 题解

   2019 GDUT Winter Training II (背包/基础DP/LIS/LCS/概率DP) 题解

                                                 A题

题面:

                                            A - 送快弟

现在我们有N个配件,他们有不同的价值. 但是我们背包的容量是有限的,因为我们只有一个一级包, 所以我们最多可以装V重量的东西. 但是为了能更好的吃到鸡(不存在的)我们要携带更有价值的配件,请问我们最多能拿多少价值的配件来当快递员呢?? 

Input

输入的第一行是T, 表示有一共要打T场比赛.

每组数据由三行组成.

第一行包含两个整数N和V(N <= 1000, V <= 1000). N表示配件的个数, V表示一级包的大小(系统会更新嘛).

第二行包含N个整数, 表示每一个配件的价值.

第三行包含N个整数, 表示每个配件的重量.

Output

对每一组数据, 输出我们最多能拿多少价值的配件.

Sample Input

1
10 10
1 3 5 7 9 11 13 15 17 19
19 17 15 13 11 9 7 5 3 1

Sample Output

51

题面描述:

            这个题目讲述的是,有一个容量为V的背包,然后有n件物品进行选择,这n件物品有各自的重量和价值,问如何尽可能地去利用背包的容量,以使背包内物品的总价值最大。

题目分析:

            这是一个经典的01背包问题,很容易想到,以这n个物品作为阶段,以背包当前的容量为状态,状态转移方程就是如果当前背包容量为V的情况下,我不选择第i件物品得到的'最大价值和选择第i件物品得到的最大价值进行比较后的最大值。最后背包容量为V的最大价值即为题目所求。

代码:

#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define reg register
#define ll long long
#define ull unsigned long long
#define bll __int128
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define lowbit(x) x&(-x)
using namespace std;
const int Maxn=1005;
const int Maxv=1005;
struct Fitting
{
	int weight,value;
};
Fitting fitting[Maxn];
int value[Maxv];
int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		int N,V;
		scanf("%d%d",&N,&V);
		memset(value,0,sizeof(value));
		for (reg int i=1;i<=N;i++) scanf("%d",&fitting[i].value);
		for (reg int i=1;i<=N;i++) scanf("%d",&fitting[i].weight);
		for (reg int i=1;i<=N;i++)
		  for (reg int j=V;j>=fitting[i].weight;j--) value[j]=max(value[j],value[j-fitting[i].weight]+fitting[i].value);
		printf("%d\n",value[V]);
	}
	return 0;
}

 

                                                 B题

题面:

                                               B - CD

You have a long drive by car ahead. You have a tape recorder, but unfortunately your best music is on CDs. You need to have it on tapes so the problem to solve is: you have a tape N minutes long. How to choose tracks from CD to get most out of tape space and have as short unused space as possible.

Assumptions:

  • number of tracks on the CD. does not exceed 20
  • no track is longer than N minutes
  • tracks do not repeat
  • length of each track is expressed as an integer number
  • N is also integer

Program should find the set of tracks which fills the tape best and print it in the same sequence as the tracks are stored on the CD

Input

Any number of lines. Each one contains value N, (after space) number of tracks M and durations of the tracks. For example from first line in sample data: N=5, M=3, first track lasts for 1 minute, second one 3 minutes, next one 4 minutes

The input data satisfies the following constraints:

N≤10000 
M≤20

Output

Set of tracks (and durations) which are the correct solutions and string ``sum:" and sum of duration times.

Sample Input

5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2

Sample Output

1 4 sum:5
8 2 sum:10
10 5 4 sum:19
10 23 1 2 3 4 5 7 sum:55
4 10 12 9 8 2 sum:45

题面描述:

            题目意思大概是输入一个CD总分钟长度N,然后输入轨道数M,然后后面输入M个轨道对应各自的时间,题目要求的是,怎样选择这M个轨道,使得这个CD上轨道分钟数最大并且不超过N,并且要输出你选择的轨道相对应的分钟数,按照题目输入的顺序来输出。

题目分析:

            这道题明显也是一道经典的01背包问题,只是在求最大CD轨道分钟数上加上记录选择轨道的相应的分钟数,因此我们做这道题的时候,不能像上一题一样用一个一维去进行DP,我们要特别开多一维空间来记录我们选择的轨道编号,最后我们可以用一个递归把我们选择的轨道相对应的分钟数输出出来,然后再把CD上轨道最长分钟数输出出来。

代码:

#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define reg register
#define ll long long
#define ull unsigned long long
#define bll __int128
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define lowbit(x) x&(-x)
using namespace std;
const int Maxn=1e4+5;
const int Maxm=25;
struct DP
{
	int id,previous,num;
};
DP dp[Maxm][Maxn];
int tracks[Maxm];
bool sign[Maxn];
int n,m;
void op(int id,int n)
{
	if (n==0) return;
	op(dp[id][n].previous,n-tracks[id]);
	printf("%d ",tracks[id]);
}
int main()
{
	while (~scanf("%d",&n))
	{
		scanf("%d",&m);
		memset(sign,0,sizeof(sign));
		memset(dp,0,sizeof(dp));
		sign[0]=1;
		int maxn=0,maxid=0;
		for (reg int i=1;i<=m;i++) scanf("%d",&tracks[i]);
		for (reg int i=1;i<=m;i++)
		{
			for (reg int j=0;j<=n;j++) dp[i][j]=dp[i-1][j];
			for (reg int j=n;j>=tracks[i];j--)
		  	if (sign[j-tracks[i]] && dp[i-1][j-tracks[i]].num+1>dp[i][j].num)
		  	{
		  		sign[j]=1;
				dp[i][j].id=i;
				dp[i][j].previous=dp[i-1][j-tracks[i]].id;
				dp[i][j].num=dp[i-1][j-tracks[i]].num+1;
				if (j>maxn)
				{
					maxn=j;maxid=i;
				}
			}
		}
		op(maxid,maxn);
		printf("sum:%d\n",maxn);
	}
	return 0;
}

 

 

                                                 C题

题面:

                                   C - Unidirectional TSP

Problems that require minimum paths through some domain appear in many different areas of computer science. For example, one of the constraints in VLSI routing problems is minimizing wire length. The Traveling Salesperson Problem (TSP) — finding whether all the cities in a salesperson’s route can be visited exactly once with a specified limit on travel time — is one of the canonical examples of an NP-complete problem; solutions appear to require an inordinate amount of time to generate, but are simple to check. This problem deals with finding a minimal path through a grid of points while traveling only from left to right. Given an m×n matrix of integers, you are to write a program that computes a path of minimal weight. A path starts anywhere in column 1 (the first column) and consists of a sequence of steps terminating in column n (the last column). A step consists of traveling from column i to column i + 1 in an adjacent (horizontal or diagonal) row. The first and last rows (rows 1 and m) of a matrix are considered adjacent, i.e., the matrix “wraps” so that it represents a horizontal cylinder. Legal steps are illustrated on the right. The weight of a path is the sum of the integers in each of the n cells of the matrix that are visited. For example, two slightly different 5×6 matrices are shown below (the only difference is the numbers in the bottom row). The minimal path is illustrated for each matrix. Note that the path for the matrix on the right takes advantage of the adjacency property of the first and last rows.

Input

The input consists of a sequence of matrix specifications. Each matrix specification consists of the row and column dimensions in that order on a line followed by m · n integers where m is the row dimension and n is the column dimension. The integers appear in the input in row major order, i.e., the first n integers constitute the first row of the matrix, the second n integers constitute the second row and so on. The integers on a line will be separated from other integers by one or more spaces. Note: integers are not restricted to being positive. There will be one or more matrix specifications in an input file. Input is terminated by end-of-file. For each specification the number of rows will be between 1 and 10 inclusive; the number of columns will be between 1 and 100 inclusive. No path’s weight will exceed integer values representable using 30 bits.

Output

Two lines should be output for each matrix specification in the input file, the first line represents a minimal-weight path, and the second line is the cost of a minimal path. The path consists of a sequence of n integers (separated by one or more spaces) representing the rows that constitute the minimal path. If there is more than one path of minimal weight the path that is lexicographically smallest should be output. Note: Lexicographically means the natural order on sequences induced by the order on their elements.

Sample Input

5 6

3 4 1 2 8 6

6 1 8 2 7 4

5 9 3 9 9 5

8 4 1 3 2 6

3 7 2 8 6 4

5 6

3 4 1 2 8 6

6 1 8 2 7 4

5 9 3 9 9 5

8 4 1 3 2 6

3 7 2 1 2 3

2 2

9 10 9 10

Sample Output

1 2 3 4 4 5

16

1 2 1 5 4 5

11

1 1

19

题面描述:

            这个题目讲述的是,输入一个m*n的矩阵,我们从第一列的任意一行出发,然后我在该行可以选择下一列的该行,上一行以及下一行,这个矩阵十分特别,可以看成是一个圆柱,即第一行的上一行是最后一行,最后一行的下一行就是第一行,问我们根据以上规则,从第一列到达最后一列的过程中遍历到的数总和的最大值。

题目分析:

             这个题目很明显就是一道DP题,我们以每一列作为阶段,每一行作为状态,状态转移方程即为从上一列的上一行,当前行和下一行的最大值加上矩阵上这个位置的数即为从第一列到达这个位置的最优方案下的数字总和,最后从最后一列当中找到一个最大值,并且将它记录下来,并且把从第一列到达这个位置的最优方案输出出来。值得注意的是,进行比较的时候,如果两种方案得到的总和是一样的,那么字典序最小的为最优,所以我们进行比较的时候要加入这个条件,最后输出最优方案即可。

注意:这道题目编写代码的时候,我们要注意数组越界的问题。

代码:

#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define reg register
#define ll long long
#define ull unsigned long long
#define bll __int128
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define lowbit(x) x&(-x)
using namespace std;
const int Maxm=105;
const int Maxn=105;
struct node
{
	int sum,p[Maxn];
};
node dp[Maxn][Maxm];
int matrix[Maxm][Maxn];
node comp(int n,node a,node b)
{
	if (a.sum<b.sum) return a;
	if (a.sum>b.sum) return b;
	for (reg int i=1;i<n;i++)
	{
		if (a.p[i]<b.p[i]) return a;
		if (a.p[i]>b.p[i]) return b;
	}
	return a;
}
int main()
{
	int m,n;
	while (~scanf("%d%d",&m,&n))
	{
		memset(dp,0,sizeof(dp));
		for (reg int i=1;i<=m;i++)
		{
			for (reg int j=1;j<=n;j++) scanf("%d",&matrix[i][j]);
			dp[1][i].sum=matrix[i][1];
			dp[1][i].p[1]=i;
		}
		for (reg int i=2;i<=n;i++)
		{
			dp[i][1]=comp(i,dp[i-1][1],dp[i-1][2]);
			dp[i][1]=comp(i,dp[i][1],dp[i-1][m]);
			dp[i][1].p[i]=1;
			dp[i][1].sum+=matrix[1][i];
			dp[i][m]=dp[i-1][m];
			if (m>1) dp[i][m]=comp(i,dp[i-1][m-1],dp[i-1][m]);
			dp[i][m]=comp(i,dp[i][m],dp[i-1][1]);
			dp[i][m].p[i]=m;
			dp[i][m].sum+=matrix[m][i];
			for (reg int j=2;j<=m-1;j++)
			{
				dp[i][j]=comp(i,dp[i-1][j-1],dp[i-1][j]);
				dp[i][j]=comp(i,dp[i][j],dp[i-1][j+1]);
				dp[i][j].p[i]=j;
				dp[i][j].sum+=matrix[j][i];
			}
		}
		node ans=dp[n][1];
		for (reg int i=2;i<=m;i++) ans=comp(n,ans,dp[n][i]);
		for (reg int i=1;i<n;i++) printf("%d ",ans.p[i]);
		printf("%d\n",ans.p[n]);
		printf("%d\n",ans.sum);
	}
	return 0;
}

 

 

                                                 D题

题面:

                                            D - 猪钱罐

在 ACM 能够开展之前,必须准备预算,并获得必要的财力支持。该活动的主要收入来自于 Irreversibly Bound Money (IBM)。思路很简单。任何时候,某位 ACM 会员有少量的钱时,他将所有的硬币投入到小猪储钱罐中。这个过程不可逆,因为只有把小猪储钱罐打碎才能取出硬币。在足够长的时间之后,小猪储钱罐中有了足够的现金,用于支付 ACM 活动所需的花费。

但是,小猪储钱罐存在一个大的问题,即无法确定其中有多少钱。因此,我们可能在打碎小猪储钱罐之后,发现里面的钱不够。显然,我们希望避免这种不愉快的情况。唯一的可能是,称一下小猪储钱罐的重量,并尝试猜测里面的有多少硬币。假定我们能够精确判断小猪储钱罐的重量,并且我们也知道给定币种的所有硬币的重量。那么,我们可以保证小猪储钱罐中最少有多少钱。

你的任务是找出最差的情形,即判断小猪储钱罐中的硬币最少有多少钱。我们需要你的帮助。不能再贸然打碎小猪储钱罐了!

输入

输入包含 T 组测试数据。输入文件的第一行,给出了 T 的值。

对于每组测试数据,第一行包含 E 和 F 两个整数,它们表示空的小猪储钱罐的重量,以及装有硬币的小猪储钱罐的重量。两个重量的计量单位都是 g (克)。小猪储钱罐的重量不会超过 10 kg (千克),即 1 <= E <= F <= 10000 。每组测试数据的第二行,有一个整数 N (1 <= N <= 500),提供了给定币种的不同硬币有多少种。接下来的 N 行,每行指定一种硬币类型,每行包含两个整数 P 和 W (1 <= P <= 50000,1 <= W <=10000)。P 是硬币的金额 (货币计量单位);W 是它的重量,以 g (克) 为计量单位。

输出

对于每组测试数据,打印一行输出。每行必须包含句子 “The minimu

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值