bzoj1237 [SCOI2008]配对
Posted wfj_2048
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1237 [SCOI2008]配对相关的知识,希望对你有一定的参考价值。
Description
你有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是不允许的,因 为相同的数不许配对。
Input
第一行为一个正整数n,接下来是n 行,每行两个整数Ai和Bi,保证所有 Ai各不相同,Bi也各不相同。
Output
输出一个整数,即配对整数的差的绝对值之和的最小值。如果无法配对,输 出-1。
Sample Input
3
3 65
45 10
60 25
3 65
45 10
60 25
Sample Output
32
HINT
1 <= n <= 10^5,Ai和Bi均为1到10^6之间的整数。
正解:$dp$。
因为每个数只出现一次,所以我们可以发现一个很显然的事,就是$a[i]$只会和$b[i-1],b[i],b[i+1]$匹配。
然后我们就可以$dp$了。设$f[i]$表示匹配了前$i$位的最小值。
于是$f[i]=max(f[i-1]+val,f[i-2]+val,f[i-3]+val)$,$val$为对应权值,当然还要判断一下合法性。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define inf (1LL<<60) 6 #define N (100010) 7 8 using namespace std; 9 10 int a[N],b[N],p[3],n; 11 ll f[N]; 12 13 il int gi(){ 14 RG int x=0,q=1; RG char ch=getchar(); 15 while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar(); 16 if (ch==‘-‘) q=-1,ch=getchar(); 17 while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar(); 18 return q*x; 19 } 20 21 int main(){ 22 #ifndef ONLINE_JUDGE 23 freopen("match.in","r",stdin); 24 freopen("match.out","w",stdout); 25 #endif 26 n=gi(); for (RG int i=1;i<=n;++i) a[i]=gi(),b[i]=gi(); 27 sort(a+1,a+n+1),sort(b+1,b+n+1); 28 if (n==1){ 29 if (a[1]==b[1]) puts("-1"); 30 else cout<<abs(a[1]-b[1]); return 0; 31 } 32 for (RG int i=1;i<=n;++i){ 33 f[i]=inf; if (a[i]!=b[i]) f[i]=min(f[i],f[i-1]+abs(a[i]-b[i])); 34 if (i>=2){ 35 if (a[i]!=b[i] && a[i-1]!=b[i-1]) 36 f[i]=min(f[i],f[i-2]+abs(a[i]-b[i])+abs(a[i-1]-b[i-1])); 37 else f[i]=min(f[i],f[i-2]+abs(a[i]-b[i-1])+abs(a[i-1]-b[i])); 38 } 39 if (i>=3){ 40 p[0]=0,p[1]=1,p[2]=2; 41 do{ 42 if (a[i]!=b[i-p[0]] && a[i-1]!=b[i-p[1]] && a[i-2]!=b[i-p[2]]) 43 f[i]=min(f[i],f[i-3]+abs(a[i]-b[i-p[0]])+abs(a[i-1]-b[i-p[1]])+abs(a[i-2]-b[i-p[2]])); 44 }while (next_permutation(p,p+3)); 45 } 46 } 47 cout<<f[n]; return 0; 48 }
以上是关于bzoj1237 [SCOI2008]配对的主要内容,如果未能解决你的问题,请参考以下文章