BZOJ-1237 [SCOI2008]配对(dp)
题目描述
给一个长为 \(n\) 的序列 \(a=[a_1,a_2,\cdots,a_n]\) 和一个长为 \(n\) 的序列 \(b=[b_1,b_2,\cdots,b_n]\)(保证所有 \(a_i\) 互不相同,所有 \(b_i\) 互不相同),把它们配对,即每个 \(a_i\) 对应一个 \(b_i\),要求所有配对的整数差的绝对值之和尽量小,但不允许两个相同的数配对。如果无法配对,输出 \(-1\)。
数据范围:\(1\leq n\leq 10^5,1\leq a_i,b_i\leq 10^6\)。
分析
假设不考虑不允许相同的数配对的限制,则把两个序列排序后对应项一一匹配就是最优答案。
现在考虑限制条件,且只考虑前 \(i\) 对数,由于保证 $a_i $ 互不相同, \(b_i\) 互不相同,所以排序后如果有 \(a_i=b_i\),则一定有 \(a_i\neq b_{i-1},a_{i}\neq b_{i-2},b_i\neq a_{i-1},b_i\neq a_{i-2}\)。有如下匹配方案:
\(0.\) \(a_{i}\) 匹配 \(b_{i}\)(\(a_i\neq b_i\))。
$ 1.$ \(a_{i-1}\) 匹配 \(b_i\),\(a_i\) 匹配 \(b_{i-1}\)。
$ 2.$ \(a_{i}\) 匹配 \(b_{i-2}\),\(a_{i-1}\) 匹配 \(b_{i-1}\),\(a_{i-2}\) 匹配 \(b_{i}\)。
$ 3.$ $a_{i} $ 匹配 \(b_{i-1}\),$a_{i-1} $ 匹配 $b_{i-2} \(,\)a_{i-2} $ 匹配 \(b_i\)。
\(4.\) \(a_i\) 匹配 \(b_{i-2}\),\(a_{i-1}\) 匹配 \(b_i\),\(a_{i-2}\) 匹配 \(b_{i-1}\)。
因此可以归纳出一个结论:每个数 \(a\) 与其匹配的数 \(b\) 下标之差不会超过 \(2\)。
设 \(dp[i]\) 表示前 \(i\) 对数配对能得到的最小值。\(dp[1]=|a_1-b_1|,dp[2]=\min(dp[1]+|a_2-b_2|,|a_1-b_2|+|a_2-b_1|)\)(如果 \(n=1\) 且 \(a_1=b_1\) 将其特判掉)。
接下来考虑状态转移方程:
方案 \(0\):\(dp[i]=dp[i-1]+|a_i-b_i|\)。
方案 \(1\):\(dp[i]=\min(dp[i],dp[i-2]+|a_i-b_{i-1}|+|a_{i-1}-b_i|)\)。
方案 \(2\):$dp[i]=\min(dp[i],dp[i-3]+|a_i-b_{i-2}|+|a_{i-1}-b_{i-1}|+|a_{i-2}-b_i|) $。
方案 \(3\):\(dp[i]=\min(dp[i],dp[i-3]+|a_i-b_{i-1}|+|a_{i-1}-b_{i-2}|+|a_{i-2}-b_i|)\)。
方案 \(4\):\(dp[i]=\min(dp[i],dp[i-3]+|a_{i}-b_{i-2}|+|a_{i-1}-b_{i}|+|a_{i-2}-b_{i-1}|)\)。
\(dp[n]\) 即为答案,时间复杂度 \(O(n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const long long INF=1e18;
long long n,dp[N],a[N],b[N];
long long ABS(long long a,long long b)
{
if(a==b)
return INF;
return abs(a-b);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d %d",&a[i],&b[i]);
sort(a+1,a+1+n);
sort(b+1,b+1+n);
if(n==1&&a[1]==b[1])
{
puts("-1");
return 0;
}
dp[1]=ABS(a[1],b[1]);
dp[2]=min(dp[1]+ABS(a[2],b[2]),ABS(a[1],b[2])+ABS(a[2],b[1]));
for(int i=3;i<=n;i++)
{
dp[i]=dp[i-1]+ABS(a[i],b[i]);
dp[i]=min(dp[i],dp[i-2]+ABS(a[i],b[i-1])+ABS(a[i-1],b[i]));
dp[i]=min(dp[i],dp[i-3]+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]+ABS(a[i],b[i-1])+ABS(a[i-1],b[i-2])+ABS(a[i-2],b[i]));
dp[i]=min(dp[i],dp[i-3]+ABS(a[i],b[i-2])+ABS(a[i-1],b[i])+ABS(a[i-2],b[i-1]));
}
cout<<dp[n]<<endl;
return 0;
}
posted on 2020-12-13 15:07 DestinHistoire 阅读(51) 评论(0) 编辑 收藏 举报