Kickstart Round F 2017 Problem B. Dance Battle

Problem

Your team is about to prove itself in a dance battle! Initially, your team has E points of energy, and zero points of honor. There are N rival teams who you must face; the i-th of these teams is the i-th in a lineup, and has a dancing skill of Si.

In each round of battle, you will face the next rival team in the lineup, and you can take one of the following actions:

  1. Dance: Your team loses energy equal to the dancing skill of the rival team, and that team does not return to the lineup. You gain one point of honor. You cannot take this action if it would make your energy drop to 0 or less.
  2. Delay: You make excuses ("our shoes aren't tied!") and the rival team returns to the back of the lineup. Your energy and honor do not change.
  3. Truce: You declare a truce with the rival team, and that team does not return to the lineup. Your energy and honor do not change.
  4. Recruit: You recruit the rival team onto your team, and that team does not return to the lineup. Your team gains energy equal to the dancing skill of the rival team, but you lose one point of honor. You cannot take this action if it would make your honor drop below 0.

The battle is over when there are no more rival teams in the lineup. If you make optimal decisions, what is the maximum amount of honor you can have when the battle is over?

Input

The first line of the input gives the number of test cases, TT test cases follow; each consists of two lines. The first line consists of two integers E and N: your team's energy, and the number of rival teams. The second line consists of N integers Si; the i-th of these represents the dancing skill of the rival team that is i-th in line at the start of the battle.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the maximum amount of honor you can have when the battle is over.

Limits

1 ≤ T ≤ 100.
1 ≤ E ≤ 106.
1 ≤ Si ≤ 106, for all i.

Small dataset

1 ≤ N ≤ 5.

Large dataset

1 ≤ N ≤ 1000.

Sample


Input 
 

Output 
 
2
100 1
100
10 3
20 3 15

Case #1: 0
Case #2: 1

In Sample Case #1, there is only one rival team. You cannot dance against them because it would make your energy fall to 0, and you cannot recruit them because it would make your honor fall below 0. Delaying does not help, so the only option is to declare a truce. You finish with 0 honor.

扫描二维码关注公众号,回复: 4641224 查看本文章

In Sample Case #2, one optimal strategy is:

  1. Delay against the first rival team. They go to the back of the lineup.
  2. Dance against the second rival team. Your energy drops to 7, and your honor increases to 1.
  3. Recruit the third rival team. Your energy increases to 22, and your honor decreases to 0.
  4. Dance against the first rival team (which is now at the head of the lineup again). Your energy drops to 2, and your honor increases to 1.

You finish with 1 point of honor.

题目理解:

你所在的队伍和其他队伍比赛跳舞,自己的队伍有体力值E和荣誉值H,竞争队伍有技术值S,与每一支队伍比赛时,有四种策略:

1.比赛,失去与对方S值相当的体力,获得一点荣誉值

2.放弃本轮比赛,对方队伍返回队列尾部

3.放弃所有与这支队伍的比赛

4.吸收这支队伍,获得与S值相当的体力,减少一点荣誉值

在比赛过程中,体力值不能小于或等于0,荣誉值不能小于0,问荣誉值最高能有多少

解题思路:

首先我们分析比赛规则,既可以放弃本轮比赛,又可以放弃所有比赛,因此,我们可以以任意顺序与所有比赛队伍比赛。其次,打败任何队伍都只获得1荣誉值,吸收任何队伍也都只失去一点荣誉值,因此我们一定选择打败S值小的队伍,吸收S值大的队伍。

经过上面的分析,我们首先可以按照S值对所有队伍进行排序,每次打败S值最小的,吸收S值最大的,但是每次打败多少支队伍,吸收多少支队伍能够得到最多的荣誉值,这个没有好的策略。我们考虑动态规划。

用dp[i,j]表示打败了i支队伍,吸收了j支队伍后的体力值,这里一定有i >= j,因为i - j就是冗余值,同时显然必须满足dp[i, j] > 0。递推公式如下:

dp[i, j] = dp[i - 1, j] - S[i],dp[i - 1, j] > S[i] && i - 1 >= j

此时表示,在吸收j支队伍,并且打败i - 1支队伍之后,还有体力打败第i支队伍

或者

dp[i, j] = dp[i, j - 1] + S[j],dp[i, j - 1] > 0

此时表示,在吸收了j - 1支队伍,并且打败i支队伍之后,再吸收第j支队伍

如果两种情况都不能满足,那么说明不可能存在吸收j支队伍,打败i支队伍的情况;若果存在,则更新荣誉值,荣誉值就是i - j

代码如下:

public class Solution {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int count = sc.nextInt();
		for(int ct = 1; ct <= count; ct++) {
			int energy = sc.nextInt(), len = sc.nextInt();
			int[] nums = new int[len];
			for(int i = 0; i < len; i++)
				nums[i] = sc.nextInt();
			Arrays.sort(nums);
			int res = 0;
			int[][] dp = new int[len + 1][len +1];
			for(int i = 0; i < len + 1; i++) {
				if(i == 0)
					dp[i][0] = energy;
				else
					dp[i][0] = dp[i - 1][0] - nums[i - 1];
				if(dp[i][0] <= 0)
					break;
				res = i;
			}
			for(int i = 1; i < len + 1; i++) {
				for(int j = 1; j <= i; j++) {
					if(i - 1 >= j && dp[i - 1][j] > 0)
						dp[i][j] = dp[i - 1][j] - nums[i - 1];
					if(dp[i][j - 1] > 0) {
						dp[i][j] = dp[i][j - 1] + nums[len - j];
					}
					if(dp[i][j] > 0)
						res = Math.max(res, i - j);
				}
			}
			System.out.println("Case #" + ct + ": " + res);
		}
		sc.close();
	}

}

猜你喜欢

转载自blog.csdn.net/m0_37889928/article/details/83003444