zoukankan      html  css  js  c++  java
  • [SCOI2008]配对 (贪心,动态规划)

    题目链接

    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
    ",f[n]);
    }
    
  • 相关阅读:
    hibernate一对多查询
    hibernate关联关系查询
    Cookie&&session
    JSP&&EL&&JSTL
    servlet下的request&&response
    servlet
    mysql命令
    html小结
    RabbitMQ初步学习和使用
    爬虫简单案例
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9379865.html
Copyright © 2011-2022 走看看