HDU 3362 Fix
状压DP。
首先很容易想到:一个点要被固定的话,必须有两个已经固定了的点与这个点连边。
再看N的范围,秒想到状压DP,秒出思路。1表示这个点已经被固定,0表示还没被固定。
推导某个状态的时候,枚举一下这个状态下所有被固定的点哪个是最后被固定的,即可得出这个状态的最优解。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n; struct Point { int x; int y; int flag; }p[20]; double dp[600000]; double dis[20][20]; double tmp[20]; int base[20]; bool cmp(const Point&a, const Point&b) { return a.flag>b.flag; } void read() { for (int i = 0; i<n; i++) scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].flag); sort(p, p + n, cmp); } void init() { for (int i = 0; i < (1 << n) + 10; i++) dp[i] = 999999999.0; for (int i = 0; i<n; i++) { for (int j = 0; j<n; j++) { if (i == j) dis[i][j] = 999999999.0; else dis[i][j] = sqrt((p[i].x - p[j].x)*(p[i].x - p[j].x) + (p[i].y - p[j].y)*(p[i].y - p[j].y)); } } } void work() { int pos = -1; for (int i = 0; i<n; i++) { if (p[i].flag==1) pos = i; else break; } if (pos == -1) printf("No Solution\n"); else if (pos+1 < 2 ) { if (n != pos + 1) printf("No Solution\n"); else printf("0.000000\n"); } else { for (int i = 0; i<(1 << (pos + 1)); i++) dp[i] = 0; for (int i = pos + 1; i<n; i++) { int state = (1 << (pos + 1)) - 1 + (1 << i); for (int k = 0; k <= pos; k++) tmp[k] = dis[i][k]; sort(tmp, tmp + pos + 1); dp[state] = tmp[0] + tmp[1]; } for (int i = (1 << (pos + 1)); i<(1 << n); i++) { if (dp[i] != 999999999.0) continue; int temp = i, tot = 0; while (temp) base[tot++] = temp % 2, temp = temp / 2; bool fail = 0; for (int k = 0; k <= pos; k++) if (!base[k]) fail = 1; if (fail) continue; for (int k = pos + 1; k < tot; k++) { if (base[k]) { int u = 0; for (int s = 0; s<tot; s++) { if (s == k) continue; if (base[s]) tmp[u++] = dis[k][s]; } sort(tmp, tmp + u); dp[i] = min(dp[i], dp[i - (1 << k)] + tmp[0] + tmp[1]); } } } printf("%.6lf\n", dp[(1 << n) - 1]); } } int main() { while (~scanf("%d", &n)) { if (!n) break; read(); init(); work(); } return 0; }