Question 3
// 也看到了其他解答,但是都只是考虑到一定有答案的测试用例,或者代码有bug,所以才写出这个答案
小a和小b玩一个游戏,有n张卡牌,每张上面有两个正整数x,y。取一张牌时,个人积分增加x,团队积分增加y。求小a,小b各取若干张牌,使得他们的个人积分相等,且团队积分最大。
输入描述:
第一行n
接下来n行,每行两个正整数x,y
输出描述:
一行一个整数
表示小a的积分和小b的积分相等时,团队积分的最大值
例:输入
4
3 1
2 2
1 4
1 4
输出:10
说明:当a抽取(2,2),b抽取(1,4),(1,4)时,两人个人积分都是2,团队积分最大,为10分
解析:可以使用动态规划解决
设:
有n张扑克牌,扑克牌上的个人积分存储为vx,团队积分存储为vy,个人积分的和为sumx
vp[i,j]为选择到第i张扑克牌,个人积分差值为j时的团队积分,有:
状态转移公式:
注:vx和vy根据vy降序排序。特别注意在公式中的 和
可能不存在有效值,还有就是在i=0时有一些选择是禁忌项(不可达选项, 所有不可达的项设置为-1) , vp为n * (sumx + 1) 的二维数组。
有初始化值:
// 状态转移公式中的值也要讨论,展开比较复杂(写公式麻烦),代码中有体现。
Java实现 :
import java.util.Scanner;
public class SelectCard2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] vx = new int[n];
int[] vy = new int[n];
int sumx = 0;
for (int i = 0; i < n; i++) {
vx[i] = in.nextInt();
vy[i] = in.nextInt();
sumx += vx[i];
}
in.close();
sort(vx, vy);
int[][] vp = new int[n][sumx + 1];
for (int i = 0; i < sumx + 1; i++) {
vp[0][i] = -1;
}
vp[0][0] = 0; //
vp[0][vx[0]] = vy[0];
for (int i = 1; i < n; i++) {
for (int j = 0; j < sumx + 1; j++) {
int Non = vp[i - 1][j];
int BHave = j - vx[i] < 0 || vp[i - 1][j - vx[i]] < 0 ? -1 : vp[i - 1][j - vx[i]] + vy[i];
int AHave = j + vx[i] >= sumx + 1 || vp[i - 1][j + vx[i]] < 0 ? -1 : vp[i - 1][j + vx[i]] + vy[i];
int tmp = Non > BHave ? Non : BHave;
vp[i][j] = tmp > AHave ? tmp : AHave;
}
}
System.out.println(vp[n - 1][0]);
}
public static void sort(int[] vx, int[] vy) {
int rows = vx.length;
for (int i = 0; i < rows; i++) {
for (int j = i + 1; j < rows; j++) {
if (vy[i] < vy[j]) {
swap(vy, i, j);
swap(vx, i, j);
}
}
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
测试用例
1. //题目提供的测试用例
2.
输入:
4
1 4
1 4
2 2
3 15
输出:
21
3. 无解测试用例
输入:
2
1 3
2 4
输出:
0