洛谷 P2507 [SCOI2008]配对

P2507 [SCOI2008]配对

 


 

题目背景

四川NOI2008省选

题目描述

你有 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 <= 104

100%的数据满足:1 <= n <= 105,Ai和Bi均为1到106之间的整数。

 思路:

这道题需要知道一个类似结论的东西:将A,B排序,每个位置与他配对的位置距离不会超过2. 
具体的证明我也不会不过可以感性的理解一下。 
假设没有不允许相同的数配对这个限制,那么最优的决策就是分别排序后相同位置的数配对。 
现在有了限制,我们就需要交换一下配对,交换的越多和会越大,所以一定是尽可能隔着比较近的数进行交换。 
如果相邻两个都与同位置的相同,那么可以使他们交换一下。 
如果相邻的三个位置都相同,可以三个人换一下。最多三个一定可以存在合法的交换方案。数量再多就可以拆分。 
知道了这就可以DP一下。 
这里写图片描述 
四种情况分类讨论一下就可以了。

错因:

1.抬头,看见上面的数据范围了吗?我一直以为是105和106结果一直RE,结果是10^5。

2.最大值竟然那么大,0x7f7f7f7f竟然取小了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[100005],b[100005];
long long f[100005];
long long col(int x,int y){
    if(a[x]==b[y])    return 0x7f7f7f7f7f;
    else return abs(a[x]-b[y]);
}
int main(){
    scanf("%d",&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);
    for(int i=0;i<=n;i++)    f[i]=0x7f7f7f7f7f;
    f[0]=0;
    for(int i=1;i<=n;i++){
        if(i>=1)    f[i]=min(f[i],f[i-1]+col(i,i));
        if(i>=2)    f[i]=min(f[i],f[i-2]+col(i,i-1)+col(i-1,i));
        if(i>=3)    f[i]=min(f[i],f[i-3]+col(i,i-1)+col(i-1,i-2)+col(i-2,i));
        f[i]=min(f[i],f[i-3]+col(i-2,i-1)+col(i-1,i)+col(i,i-2));
    }
    cout<<f[n];
}

 

posted @ 2017-09-18 15:54  一蓑烟雨任生平  阅读(164)  评论(0编辑  收藏  举报