【BZOJ-1237】配对(dp)

版权声明:如果有什么问题,欢迎大家指出,希望能和大家一起讨论、共同进步。 https://blog.csdn.net/QQ_774682/article/details/83855782

你有n 个整数Ai和n 个整数Bi。你需要把它们配对,即每个Ai恰好对应一 个Bp[i]。要求所有配对的整数差的绝对值之和尽量小,但不允许两个相同的数配 对。例如A={5,6,8},B={5,7,8},则最优配对方案是5配8, 6配5, 8配7,配对整数 的差的绝对值分别为2, 2, 1,和为5。注意,5配5,6配7,8配8是不允许的,因 为相同的数不许配对。

Input

第一行为一个正整数n,接下来是n 行,每行两个整数Ai和Bi,保证所有 Ai各不相同,Bi也各不相同。

Output

输出一个整数,即配对整数的差的绝对值之和的最小值。如果无法配对,输 出-1。

Sample Input

3 3 65 45 10 60 25

Sample Output

32

Hint

1 <= n <= 10^5,Ai和Bi均为1到10^6之间的整数。

思路:

开始看着题想到了排序,但是对后面的做法没有很清晰的思路,看了大佬的博客后发现要比较以下几种情况,感觉上这样也对,可是不会证明,总之,两个数肯定不能离的很远,比如排好序中a[1]和b[n],这样的话值是比较大的,不如相邻两个之间互相交换。这道题做法是dp,某一位的最优解是有几种情况比较来确定的。

ac代码:

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring> 
#include<queue>
#include<stack> 
#include<string.h>
#include<set>
#define ll long long
#define PI acos(-1.0)
#define eps 1e-8
using namespace std;
/*
三个数之间一定会有解,不能超太远(不知道怎么证明)
所以一位之间最优,可能是这位的两个数,或者往前往后错一位,即交换一位来求,还有就是往前两个和往后两个之间互相交换。 
这里挎包房费数相同取得值是大于1e6的值,因此操作中dp循环取最小就是最优解。
开始先把前两位进行操作,之后的循环中,操作后面的,每一个都是三次比较,本位,和前一位交换,与前两位交换,
这里不进行与后面的交换,因为到后面的位置时,会补上这种情况,而且这里操作后之后还要再操作有重复。 
*/
int a[100100],b[100100];
ll dp[100100];
ll cal(ll a,ll b)
{
	return a==b?2001000:abs(a-b);
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&a[i],&b[i]);	
	} 
	if(n==1&&a[0]==b[0])
	{
		printf("-1\n");
		return 0;
	}	
	sort(a,a+n);
	sort(b,b+n);
	dp[0]=cal(a[0],b[0]);
	dp[1]=min(dp[0]+cal(a[1],b[1]),cal(a[0],b[1])+cal(a[1],b[0]));	
	for(int i=2;i<n;i++)
	{
		dp[i]=dp[i-1]+cal(a[i],b[i]);
		dp[i]=min(dp[i],dp[i-2]+cal(a[i],b[i-1])+cal(a[i-1],b[i]));
		ll tem=min(cal(a[i-2],b[i-1])+cal(a[i-1],b[i])+cal(a[i],b[i-2]),cal(a[i-2],b[i])+cal(a[i-1],b[i-2])+cal(a[i],b[i-1]));
		tem=min(tem,cal(a[i-2],b[i])+cal(a[i-1],b[i-1])+cal(a[i],b[i-2]));
		dp[i]=min(dp[i],dp[i-3]+tem);
	} 
	cout<<dp[n-1]<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/QQ_774682/article/details/83855782
今日推荐