对决 - Head to Head Showdown - DP

对决

时间限制:最多40个用例,1秒(C/C++),1.5秒(Java)/内存限制:256 MB(Stack 1 MB)

 

你负责组织A队和B队之间的围棋比赛。两支队伍决定在队员之间进行一对一比赛,但发现A队有N名队员,B队有N+1名队员。(同一队员不能参加两次比赛,而为了一对一比赛,B队中必然需要排除一名队员。)

假设已知两队队员的各自实力。为了最大程度的进行公平比赛,在一对一比赛中,双方队员之间的实力差异的绝对值总和应为最小。

例如,假设A队有五名队员,实力分别为2、6、4、10、4;B队有六名队员,实力分别为 7、9、1、6、5、10。此时,排除B队中实力为9的队员后,按照如下一样成对的进行比赛时,实力差异的绝对值总和为5,这将成为最小的情况。但如下方式并非是唯一的方式。(括号内第一个数值为A队队员的实力,第二个数值为B队队员的实力。)

 

 

 

接收两队队员的实力后,请编写出当B队伍中排除一名队员进行比赛时,两队队员实力差异的绝对值总和为最小的程序。

 

[限制条件]

1.A队的队员数N为介于1到300,000之间的整数。

2.实力值为介于1到1,000,000,000之间的整数。(注意整数的表示范围。)

 

[输入]

第一行给出测试用例数量T。随后给出T个测试用例。各个用例的第一行给出A队的队员数N。下一行空格区分给出N个A队队员各自的实力。再下一行空格区分给出N+1个B队队员各自的实力。

 

[输出]

各个测试用例的答案按照顺序标准输出。对每个用例输出“#x”(x为测试用例编号,从1开始),加一个空格后(不包含引号),输出题目中要求的最小的实力差异绝对值总和

 

[输入输出 示例]

(输入)

3

5

2 6 4 10 4

7 9 1 6 5 10

8

3 1 8 4 2 7 9 6

1 4 5 10 6 5 3 8 8

1

1

1000000000 1000000000

 

(输出)

#1 5

#2 5

#3 999999999

 

思路分析:
求实力差最小,那么肯定是小的减小的,大的减大的,所以,要对两队实力先进行排序,然后再进行计算
B队多一个人,需要去掉一个人,但是我们不知道去掉哪个是最优解,那么就把所有人都去掉试一次,典型的动态规划问题
dp[i]表示去掉第i个人后,两队实力的绝对值之和
dp[0] = Math.abs(A[0]-B[1]) + Math.abs(A[1]-B[2]) + Math.abs(A[2]-B[3]) +....
dp[1] = Math.abs(A[0]-B[0]) + Math.abs(A[1]-B[2]) + Math.abs(A[2]-B[3]) +....
dp[2] = Math.abs(A[0]-B[0]) + Math.abs(A[1]-B[1]) + Math.abs(A[2]-B[3]) +....
则: dp[2] - dp[1] = Math.abs(A[1]-B[1]) - Math.abs(A[1]-B[2]);
递推公式: dp[i] = dp[i-1] + Math.abs(A[i-1]-B[i-1]) - Math.abs(A[i-1]-B[i]);

 

package pro.dp;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * 对决
 * @author XA-GDD
 * 
 * 思路分析:
 * 求实力差最小,那么肯定是小的减小的,大的减大的,所以,要对两队实力先进行排序,然后再进行计算
 * B队多一个人,需要去掉一个人,但是我们不知道去掉哪个是最优解,那么就把所有人都去掉试一次,典型的动态规划问题
 * dp[i]表示去掉第i个人后,两队实力的绝对值之和
 * dp[0] = Math.abs(A[0]-B[1]) + Math.abs(A[1]-B[2]) + Math.abs(A[2]-B[3]) +....
 * dp[1] = Math.abs(A[0]-B[0]) + Math.abs(A[1]-B[2]) + Math.abs(A[2]-B[3]) +....
 * dp[2] = Math.abs(A[0]-B[0]) + Math.abs(A[1]-B[1]) + Math.abs(A[2]-B[3]) +....
 * 则: dp[2] - dp[1] =  Math.abs(A[1]-B[1]) - Math.abs(A[1]-B[2]);
 * 递推公式: dp[i] = dp[i-1] + Math.abs(A[i-1]-B[i-1]) - Math.abs(A[i-1]-B[i]);
 */
public class HeadToHeadShowdown_0706 {
	static int T,N;
	static int _max_Nval = 300000;
	static long [] A = new long[_max_Nval];
	static long [] B = new long[_max_Nval+1];
	static long [] dp = new long[_max_Nval+1];
	static long ANS;
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\sw_pro\\test_case\\sample_input_0706.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	    StringTokenizer st = new StringTokenizer(br.readLine());
		T = Integer.parseInt(st.nextToken());
	    for(int testCase = 1; testCase<= T;testCase++) {
	    	Arrays.fill(A, 0);
	    	Arrays.fill(B, 0);
	    	Arrays.fill(dp, 0);
	    	st = new StringTokenizer(br.readLine());
	    	N = Integer.parseInt(st.nextToken());
	    	
	    	st = new StringTokenizer(br.readLine());
	    	for(int i=0;i<N;i++) {
	    		A[i] = Integer.parseInt(st.nextToken());
	    	}
	    	
	    	st = new StringTokenizer(br.readLine());
	    	for(int i=0;i<=N;i++) {
	    		B[i] = Integer.parseInt(st.nextToken());
	    	}

	    	Arrays.sort(A,0,N);
	    	Arrays.sort(B,0,N+1);
	    	
	    	//边界值dp[0]
	    	for(int i=0;i<N;i++) {
	    		dp[0] += Math.abs(A[i]-B[i+1]);
	    	}
	    	
	    	ANS=dp[0];
	    	
	    	//根据递推公式求dp
	    	for(int i=1;i<N;i++) {
	    		dp[i] = dp[i-1] + Math.abs(A[i-1]-B[i-1]) - Math.abs(A[i-1]-B[i]);
	    		ANS = Math.min(ANS, dp[i]);
	    	}
	    	
	    	System.out.printf("#%d %d\n", testCase,ANS);
	    }	
	}

}

  

 

posted @ 2021-10-10 09:42  晓暮云  阅读(169)  评论(0)    收藏  举报