最优配对问题
最優配對問題:空間里有n個點P0,P1,…,Pn-1,你的任務是把它們配成n/2對(n是偶數),使得每個點恰好在一個點對中。所有點對中兩點的距離之和應盡量小。?
紫書:P284.還有就是劉汝佳為數不多的一個小錯誤,max (應該是min)
到網上逛了一下,果然是個經典問題。首先就是關于集合的任意子集的表示,dp的思路。
我這里寫了兩種方法,編譯不了,只不過是 dp 重命名了,主要是記錄這個思想。
dp方程:
d[i][S] 點0~i 的最優匹配,S為狀態集合。
d[i][S] = min(d[i][j],dist(i,j)+d[i-1][S-{i}-{j}]);?
集合的表示,之前我在一道最小生成樹的枚舉上用過,可以借鑒到這里來,怎么找 j 呢? 集合 S 和 j 是否有交集 (S&(1<<j)) ,出去 i j 的集合怎么表示呢? d[i-1][S^(1<<i)^(1<<j)];
這就是第一種方式。
第二種方式:
你可以發現, i ?一定是 S中最大的元素,那么dp就可以減少一維。
d(S) = min(|PiPj| + d(S-{i}-{j})) | i = max(S);
?
但是,可以發現,找最小的是可以很容易找出來的,不如,將第一種的定義修改一下。
d[i][S] i ~ n 的點,狀態集合是 S ,
那么循環順序,就是 (j = i+1;j<n;j++) 了。
?
#include <bits/stdc++.h>using namespace std;///最優配對問題 #define maxnode 5000 #define maxnodes 5000<<1 #define INF 0x3f3f3f3fint d[maxnode][maxnodes]; int n; ///點的個數int main() {///結果存在 d[n-1][(1<<n)-1]中 for(int i=0;i<n;i++) { for(int S=0;S<(1<<n);S++) { d[i][S] = INF;for(int j=0;j<i;j++) {if(S&(1<<j)) {d[i][S] = min(d[i][S],dist(i,j)+d[i-1][S^(1<<i)^(1<<j)]);}}}}///由于 i 一定是 S 中最大的元素,所以可以減少一維,///答案存在 d[(1<<n)-1] 中 for(int S=0;S<(1<<n);S++) { d[S] = INF;for(int i=0;i<n;i++) {if(S&(1<<i))break;}///這里 i 是 S 中最小的元素,如果有交集,求一下最優值for(int j=i+1;j<n;j++) {if(S&(1<<j))d[S] = max(d[S],dist(i,j)+d[S^(1<<i)^(1<<j)]);}}return 0; }?
轉載于:https://www.cnblogs.com/TreeDream/p/6011865.html
總結
- 上一篇: NSDate 时间
- 下一篇: dex-method-counts的用法