【题解】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;
}

 

posted @ 2018-02-03 00:14  Twilight_Sx  阅读(236)  评论(0编辑  收藏  举报