题目大意:给出2*n个点,将这些点配成n对,使得所有点对中两点的距离之和尽量小。
用一个整数的二进制形式表示一个集合的子集,以每个集合为状态进行状态转移。具体参见《算法竞赛入门经典》9.5。
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 #include <cfloat> 5 using namespace std; 6 7 struct Point 8 { 9 int x, y; 10 } point[20]; 11 double dp[1<<16+10]; 12 13 double dis(int a, int b) 14 { 15 int x_diff = point[a].x - point[b].x; 16 int y_diff = point[a].y - point[b].y; 17 return sqrt(x_diff * x_diff + y_diff * y_diff); 18 } 19 20 int main() 21 { 22 #ifdef LOCAL 23 freopen("in", "r", stdin); 24 #endif 25 int n, kase = 0; 26 char name[30]; 27 while (scanf("%d", &n) && n) 28 { 29 n *= 2; 30 for (int i = 0; i < n; i++) 31 scanf("%s%d%d", name, &point[i].x, &point[i].y); 32 dp[0] = 0; 33 for (int s = 1; s < (1<<n); s++) 34 { 35 dp[s] = DBL_MAX; 36 int p = 0; 37 for ( ; p < n; p++) 38 if (s & (1<<p)) break; 39 for (int i = p+1; i < n; i++) 40 if (s & (1<<i)) 41 dp[s] = min(dp[s], dis(p, i)+dp[s^(1<<p)^(1<<i)]); 42 } 43 printf("Case %d: %.2lf ", ++kase, dp[(1<<n)-1]); 44 } 45 return 0; 46 }