【题解】SCOI2008配对
贪心+dp~观察数据,发现一个规律:将数字排序之后,最优匹配只可能产生在该数字和与它距离不超过二的数字之间。
所以可以用dp[i]代表前i个数(排序)匹配的最小差值,之后暴力选出该新数应该如何匹配。
以及题目保证A[i](B[i])中所有数字互不相同,这是为了避免一种情况的出现:
1 1 5 5
5 5 1 1
此时的最优解距离就超过了二啦。这种情况我并没有想到解,也很好奇是不是能够有接受这种情况的算法。
以下我丑丑的代码……(捂脸)、+INF要开大大大大大大大大大!
#include <bits/stdc++.h>
using namespace std;
#define maxn 2500000
#define INF 9999999999LL
#define int long long
int dp[maxn], a[maxn], b[maxn], n, mark[maxn], cnt[maxn];
int read()
{
int x = 0;
char c;
c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >='0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}
int abs(int x, int y)
{
if(x == y) return INF;
else return (x - y) >= 0 ? x - y : y - x;
}
signed main()
{
n = read();
for(int i = 1; i <= n; i ++)
a[i] = read(), b[i] = read();
for(int i = 1; i <= n; i ++) dp[i] = INF;
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + n);
for(int i = 1; i <= n; i ++)
{
mark[i] += mark[i - 1];
if(a[i] == a[i - 1]) cnt[i] = cnt[i - 1] + 1;
else cnt[i] = 1;
if(a[i] == b[i]) mark[i] ++;
if(a[i] != b[i]) dp[i] = dp[i - 1] + abs(a[i], b[i]);
if(i >= 2)
{
if(a[i] != a[i - 1])
dp[i] = min(dp[i - 2] + abs(a[i], b[i - 1]) + abs(b[i], a[i - 1]), dp[i]);
if(i >= 3 && mark[i] - mark[i - 3] >= 2)
{
int tem = abs(a[i], b[i - 2]) + abs(a[i - 1], b[i]) + abs(a[i - 2], b[i - 1]);
tem = min(tem, abs(a[i], b[i - 1]) + abs(a[i - 1], b[i - 2]) + abs(a[i - 2], b[i]));
tem = min(tem, abs(a[i], b[i - 2]) + abs(a[i - 1], b[i - 1]) + abs(a[i - 2], b[i]));
dp[i] = min(dp[i], dp[i - 3] + tem);
}
}
}
if(dp[n] >= INF) printf("-1\n");
else printf("%lld\n", dp[n]);
return 0;
}