洛谷P2507 [SCOI2008]配對 題解(dp+貪心)
阿新 • • 發佈:2018-11-01
洛谷P2507 [SCOI2008]配對 題解(dp+貪心)
標籤:題解
閱讀體驗:https://zybuluo.com/Junlier/note/1299251
連結題目地址:洛谷P2507 [SCOI2008]配對
感覺是道很好的推斷題
貪心
想到貪心的結論就很容易,沒想到就很難做出來了
結論:對\(A,B\)陣列分別排序之後,在\(A\)中選第\(i\)個數,與之配對的數一定在\(B[i-1]\)~\(B[i+1]\)內
其實證明是很好證的,在與你是否往這方面想了。。。
因為題目有一個很好的性質:\(A,B\)數列中數字各不相同
所以如果沒有配對不相等的限制的話,我們肯定是排序直接減得答案是吧
那麼有限制之後,就有機會讓\(A[i]\)和\(B[i-1]\)或\(B[i+1]\)配對了吧,跳遠了顯然是不會更優的
動態規劃
那麼就可以直接\(dp\)了:\(dp[i]\)表示到第\(i\)號全部配對的最小答案
因為一個數可能與三個數配對,那麼我們可以大力討論\(dp\)了
對於限制,我們手寫一個\(ABS\),如果差為0,返回\(Inf\)就\(ok\)
dp[i]=MIN(dp[i],dp[i-1]+ABS(A[i]-B[i])); dp[i]=MIN(dp[i],dp[i-2]+ABS(A[i]-B[i-1])+ABS(A[i-1]-B[i])); 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])); 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])); 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]));
從上到下依次是:自己看一下吧。。。(草稿紙上玩結論,自己\(yy\),我懶得寫了)
那麼全部程式碼
不合法情況就是\(n==1\)並且\(A[1]==B[1]\)時
因為\(A,B\)數列中數字各不相同,所以\(n>1\)時一定可以另外配得到對
#include<bits/stdc++.h> #define il inline #define rg register #define ldb double #define lst long long #define rgt register int #define N 100050 using namespace std; const lst Inf=1e15; il int MAX(rgt x,rgt y){return x>y?x:y;} il lst MIN(rg lst x,rg lst y){return x<y?x:y;} il int read() { int s=0,m=0;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();} while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar(); return m?-s:s; } int n; lst A[N],B[N];lst dp[N]; il lst ABS(rg lst x){return x?(x>0?x:-x):(Inf);} int main() { n=read(); for(rgt i=1;i<=n;++i)A[i]=read(),B[i]=read(),dp[i]=Inf; if(n==1&&A[1]==B[1]){puts("-1");return 0;} sort(&A[1],&A[n+1]),sort(&B[1],&B[n+1]); dp[1]=ABS(A[1]-B[1]); dp[2]=MIN(dp[1]+ABS(A[2]-B[2]),ABS(A[1]-B[2])+ABS(A[2]-B[1])); for(rgt i=3;i<=n;++i) { dp[i]=MIN(dp[i],dp[i-1]+ABS(A[i]-B[i])); dp[i]=MIN(dp[i],dp[i-2]+ABS(A[i]-B[i-1])+ABS(A[i-1]-B[i])); 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])); 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])); 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])); }return printf("%lld\n",dp[n]),0; }