Written with StackEdit.
Description
你有(n) 个整数(A_i)和(n) 个整数(B_i)。你需要把它们配对,即每个(A_i)恰好对应一 个(B_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) 行,每行两个整数(A_i)和(B_i),保证所有 (A_i)各不相同,(B_i)也各不相同。
Output
输出一个整数,即配对整数的差的绝对值之和的最小值。如果无法配对,输 出(-1)。
Sample Input
3
3 65
45 10
60 25
Sample Output
32
HINT
(1 <= n <= 10^5),(A_i)和(B_i)均为(1)到(10^6)之间的整数。
Solution
第一眼费用流 然而看数据范围 显然不可做...
- 考虑先将(A)和(B)从小到大排序.
- 若没有相同的不可取的限制,显然直接贪心,(A_i)配(B_i).
- 注意到,(A_i)各不相同,(B_i)也各不相同.所以如果(A_i=B_i),那么(A_i)肯定与(B_{i-1},B_{i-2})都不相同.
- 这样容易发现,(A_{i-2},A_{i-1},A_{i},B_{i-2},B_{i-1},B_{i})两两配对是一定有合法方案的.
- 设(f[i])表示将(A_1)到(A_i),(B_1)到(B_i)两两配对的最小花费.
- 枚举,(A_{i-2},A_{i-1},A_{i},B_{i-2},B_{i-1},B_{i})两两配对的方式转移即可.
- 注意边界(f[1],f[2].)以及特判无解.
#include<bits/stdc++.h>
#define inf 1e18
using namespace std;
typedef long long LoveLive;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
{
fh=-1;
jp=getchar();
}
while (jp>='0'&&jp<='9')
{
out=out*10+jp-'0';
jp=getchar();
}
return out*fh;
}
const int MAXN=1e5+10;
int a[MAXN],b[MAXN];
inline LoveLive calc(int x,int y)
{
return x==y?inf:abs(x-y);
}
inline void upd(LoveLive &x,LoveLive y)
{
if(y<x)
x=y;
}
int n;
LoveLive f[MAXN];
void init()
{
f[0]=0;
f[1]=calc(a[1],b[1]);
f[2]=min(f[1]+calc(a[2],b[2]),calc(a[1],b[2])+calc(a[2],b[1]));
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
a[i]=read(),b[i]=read();
if(n==1 && a[1]==b[1])
{
puts("-1");
return 0;
}
sort(a+1,a+1+n);
sort(b+1,b+1+n);
init();
for(int i=3;i<=n;++i)
{
f[i]=inf;
upd(f[i],f[i-1]+calc(a[i],b[i]));
upd(f[i],f[i-2]+calc(a[i-1],b[i])+calc(a[i],b[i-1]));
upd(f[i],f[i-3]+calc(a[i],b[i-2])+calc(a[i-1],b[i-1])+calc(a[i-2],b[i]));
upd(f[i],f[i-3]+calc(a[i],b[i-1])+calc(a[i-1],b[i-2])+calc(a[i-2],b[i]));
upd(f[i],f[i-3]+calc(a[i],b[i-2])+calc(a[i-1],b[i])+calc(a[i-2],b[i-1]));
}
printf("%lld
",f[n]);
return 0;
}
开long long.