码迷,mamicode.com
首页 > 其他好文 > 详细

[SCOI2008]配对 (贪心,动态规划)

时间:2018-07-27 23:14:26      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:元素   space   return   str   name   amp   定义   注意   min   

题目链接

Solution

很妙的DP,很妙的贪心.

首先考虑,如果说没有那个相同的不能配对的情况;
那么我们肯定是直接排两遍序,然后一一对应即可.

但是是有限制的,同时我们可得几个条件供贪心:

  • 每个数字仅在 \(a\)\(b\) 中出现一次. 即每个序列排序之后满足 \(a_i≠b_i\).

  • 如果 \(a_i=b_i\) ,我们需要去和其他位置的元素交换;
  • 我们交换的元素与当前元素的绝对距离不会大于 \(2\),也就是说每次我们碰到相同的情况,只需要 \(a_i\)\(a_{i+1}\) 或者 \(a_{i-1}\) 交换.

然后我们定义 \(f[i]\) 为到第 \(i\) 个点的时候最小的差值.
考虑3个一组转移,至于为什么是3个,可以看上面的贪心条件.
令原排列为 \(a[i-2],a[i-1],a[i]\);
则有以下几种情况:

  1. \(a[i-2],a[i],a[i-1]\)
  2. \(a[i-1],a[i-2],a[i]\)
  3. \(a[i-1],a[i],a[i-2]\)
  4. \(a[i],a[i-2],a[i-1]\)
  5. \(a[i],a[i-1],a[i-2]\)

然后我们每次通过讨论从 \(f[i-3]\) 转移过来即可.
注意要预先处理 \(f[1],f[2],f[3]\) 的值.

Code

#include<bits/stdc++.h>
#define maxn 100005
#define ll long long 
using namespace std;
const ll Inf=19260817;
ll f[maxn],n,a[maxn],b[maxn];
ll cal(int x,int y)
{
    if (a[x]==b[y]) return Inf;
    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+n+1);
   sort(b+1,b+n+1);
   for (int i=1;i<=n;i++) f[i]=Inf;
   f[0]=0;
   for (int i=1;i<=n;i++) 
   {
     ll t=inf;
     if (i>=1) t=min(t,f[i-1]+cal(i,i));
     if (i>=2) t=min(t,f[i-2]+cal(i,i-1)+cal(i-1,i));
     if (i>=3) t=min(t,f[i-3]+cal(i,i-1)+cal(i-1,i-2)+cal(i-2,i)),
     t=min(t,f[i-3]+cal(i-2,i-1)+cal(i-1,i)+cal(i,i-2));
     f[i]=t;
   }
   printf("%lld\n",f[n]);
}

[SCOI2008]配对 (贪心,动态规划)

标签:元素   space   return   str   name   amp   定义   注意   min   

原文地址:https://www.cnblogs.com/Kv-Stalin/p/9379865.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!