[关闭]
@Junlier 2018-11-01T23:02:00.000000Z 字数 1918 阅读 1836

洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

题解
阅读体验:https://zybuluo.com/Junlier/note/1299251

链接题目地址:洛谷P2507 [SCOI2008]配对

感觉是道很好的推断

贪心

想到贪心的结论就很容易,没想到就很难做出来了
结论:对数组分别排序之后,中选第个数,与之配对的数一定在~
其实证明是很好证的,在与你是否往这方面想了。。。

因为题目有一个很好的性质:数列中数字各不相同
所以如果没有配对不相等的限制的话,我们肯定是排序直接减得答案是吧
那么有限制之后,就有机会让配对了吧,跳远了显然是不会更优的

动态规划

那么就可以直接了:表示到第号全部配对的最小答案
因为一个数可能与三个数配对,那么我们可以大力讨论
对于限制,我们手写一个,如果差为0,返回

  1. dp[i]=MIN(dp[i],dp[i-1]+ABS(A[i]-B[i]));
  2. dp[i]=MIN(dp[i],dp[i-2]+ABS(A[i]-B[i-1])+ABS(A[i-1]-B[i]));
  3. 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]));
  4. 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]));
  5. 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]));

从上到下依次是:自己看一下吧。。。(草稿纸上玩结论,自己,我懒得写了)

那么全部代码

不合法情况就是并且
因为数列中数字各不相同,所以时一定可以另外配得到对

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define rg register
  4. #define ldb double
  5. #define lst long long
  6. #define rgt register int
  7. #define N 100050
  8. using namespace std;
  9. const lst Inf=1e15;
  10. il int MAX(rgt x,rgt y){return x>y?x:y;}
  11. il lst MIN(rg lst x,rg lst y){return x<y?x:y;}
  12. il int read()
  13. {
  14. int s=0,m=0;char ch=getchar();
  15. while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
  16. while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
  17. return m?-s:s;
  18. }
  19. int n;
  20. lst A[N],B[N];lst dp[N];
  21. il lst ABS(rg lst x){return x?(x>0?x:-x):(Inf);}
  22. int main()
  23. {
  24. n=read();
  25. for(rgt i=1;i<=n;++i)A[i]=read(),B[i]=read(),dp[i]=Inf;
  26. if(n==1&&A[1]==B[1]){puts("-1");return 0;}
  27. sort(&A[1],&A[n+1]),sort(&B[1],&B[n+1]);
  28. dp[1]=ABS(A[1]-B[1]);
  29. dp[2]=MIN(dp[1]+ABS(A[2]-B[2]),ABS(A[1]-B[2])+ABS(A[2]-B[1]));
  30. for(rgt i=3;i<=n;++i)
  31. {
  32. dp[i]=MIN(dp[i],dp[i-1]+ABS(A[i]-B[i]));
  33. dp[i]=MIN(dp[i],dp[i-2]+ABS(A[i]-B[i-1])+ABS(A[i-1]-B[i]));
  34. 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]));
  35. 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]));
  36. 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]));
  37. }return printf("%lld\n",dp[n]),0;
  38. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注