Evanyou Blog 彩带

洛谷P2507 [SCOI2008]配对 [DP,贪心]

  题目传送门

配对

题目描述

你有 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是不允许的,因为相同的数不许配对。

输入输出格式

输入格式:

 

第一行为一个正整数n,接下来是n 行,每行两个整数Ai和Bi,保证所有

Ai各不相同,Bi也各不相同。

 

输出格式:

 

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

出-1。

 

输入输出样例

输入样例#1: 
3
3 65
45 10
60 25
输出样例#1: 
32
输入样例#2: 
3
5 5
6 7
8 8
输出样例#2: 
5

说明

30%的数据满足:n <= 10^4

100%的数据满足:1 <= n <= 10^5,Ai和Bi均为1到10^6之间的整数。

 


  分析:

  一开始打了个裸的贪心,然后30pts;然后看了five20巨佬写的正解,自己改,70pts;最后,开了long long,100pts。

  如果没有那个$a[i]\neq b[i]$的要求,那么思路就很明显,直接贪心排序然后一一配对即可。

  然后我们在观察一下,发现$a[i],b[i]$都是唯一的,那么就在这个贪心的基础上改一下,把相同的元素试着与周围的元素交换。分析可以得到,只有相邻的3对元素互相交换才能保证最优解。有了这个思路就好办了,可以把它转换成DP,并且在做的时候我们都不用特判,当$a[i]=b[i]$时直接赋值为$inf$即可。

  Code:

 

//It is made by HolseLee on 25th July 2018
//Luogu.org P2507
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+7;
const int inf=1e9+7;
ll n,a[N],b[N],dp[N],ans;

inline ll minu(ll x,ll y)
{
    return x==y?inf:(x>y?x-y:y-x);
}

inline ll Min(ll x,ll y)
{
    return x>y?y:x;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>a[i]>>b[i];
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    if(n==1&&a[1]==b[1]){
        cout<<"-1"<<"\n";return 0;
    }
    dp[1]=minu(a[1],b[1]);
    dp[2]=Min(dp[1]+minu(a[2],b[2]),minu(a[1],b[2])+minu(a[2],b[1]));
    for(int i=3;i<=n;i++){
        dp[i]=dp[i-1]+minu(a[i],b[i]);
        dp[i]=Min(dp[i],dp[i-2]+minu(a[i],b[i-1])+minu(a[i-1],b[i]));
        dp[i]=Min(dp[i],dp[i-3]+minu(a[i],b[i-2])+minu(a[i-1],b[i])+minu(a[i-2],b[i-1]));
        dp[i]=Min(dp[i],dp[i-3]+minu(a[i],b[i-1])+minu(a[i-1],b[i-2])+minu(a[i-2],b[i]));
        dp[i]=Min(dp[i],dp[i-3]+minu(a[i],b[i-2])+minu(a[i-2],b[i])+minu(a[i-1],b[i-1]));
    }
    cout<<dp[n]<<"\n";
    return 0;
}

 

posted @ 2018-07-25 22:24  HolseLee  阅读(209)  评论(0编辑  收藏  举报