洛谷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。
输入输出样例
说明
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; }
蒟蒻写博客不易,如果有误还请大佬们提出
如需转载,请署名作者并附上原文链接,蒟蒻非常感激
名称:HolseLee
博客地址:www.cnblogs.com/cytus
个人邮箱:1073133650@qq.com
如需转载,请署名作者并附上原文链接,蒟蒻非常感激
名称:HolseLee
博客地址:www.cnblogs.com/cytus
个人邮箱:1073133650@qq.com