有N个点,每次可以从起点出发到1或者2个点然后回到起点,问走过所有的点需要的最小路程(路程定义为欧氏距离的平方)。
显然,到一个点路径为S->i->S,到两个点走过的路径为S->i->j->S。状态压缩然后枚举即可。因为和顺序无关,每次只要枚举最小的没有走的点,然后枚举到这个点返回或者到这个点再去另一个点之后返回的路径长度,相同的状态取最小值即可。
1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define INF 0x3f3f3f3f 5 #define MAXS 1100000 6 using namespace std; 7 struct pnt{int x, y;}p[25]; 8 int n, cas, ans[25], anss; 9 int d[MAXS], pre[MAXS], dis[25][25]; 10 11 int lowbit(int x){return x&-x;} 12 bool cmp(const int& x, const int& y) {return lowbit(x) < lowbit(y);} 13 int sqr(int x){return x * x;} 14 int getdis(pnt p1, pnt p2){return sqr(p1.x - p2.x) + sqr(p1.y - p2.y);} 15 int main(){ 16 //freopen("test.in", "r", stdin); 17 scanf("%d", &cas); 18 for (int ca = 1; ca <= cas; ca++) { 19 scanf("%d%d", &p[0].x, &p[0].y); 20 scanf("%d", &n); 21 for (int i = 1; i <= n; i++) scanf("%d%d", &p[i].x, &p[i].y); 22 for (int i = 0; i <= n; i++) for (int j = 0; j <= n; j++) dis[i][j] = getdis(p[i], p[j]); 23 int full = 1<<n; 24 for (int i = 1; i < full; i++) d[i] = INF; 25 for (int s = 0; s < full; s++) { 26 for (int i = 0 ;i < n; i++) if(0 == (s&1<<i)){ 27 if(d[s|1<<i] > d[s] + 2 * dis[0][i+1]) { 28 d[s|1<<i] = d[s] + 2 * dis[0][i+1]; 29 pre[s|1<<i] = s; 30 } 31 for (int j = i+1, ss = 1<<i|s; j < n; j++) if(0 == (ss&1<<j)) { 32 if (d[ss|1<<j] > d[s] + dis[0][i+1] + dis[i+1][j+1] + dis[j+1][0]) { 33 d[ss|1<<j] = d[s] + dis[0][i+1] + dis[i+1][j+1] + dis[j+1][0]; 34 pre[ss|1<<j] = s; 35 } 36 } 37 break; 38 } 39 } 40 anss = 0; 41 for (int x = full -1; x != 0; x = pre[x]) { 42 ans[anss++] = x^pre[x]; 43 } 44 sort(ans, ans + anss, cmp); 45 printf("Case %d:\n", ca); 46 printf("%d\n", d[full - 1]); 47 for (int i = 0, x = 0; i < anss; i++) { 48 for (int j = 0; j < n; j++){ 49 if(ans[i]&1<<j)printf("%d%c", j+1, ++x ==n ? '\n' : ' '); 50 } 51 52 } 53 } 54 return 0; 55 }