记忆化搜索+状态压缩
用二进制的01表示是否已分配的状态。
状态:dp[x]表示在状态x下所能达到最小的距离。
状态转移:dp[x] = min(dp[x^(1<<i)^(1<<j)]+dis(i....j));
代码如下:
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; #define N 8 int n, vis[1<<2*N], x[2*N], y[2*N]; double dp[1<<2*N], f[2*N][2*N]; char str[25]; double dfs(int x) { if(vis[x]) return dp[x]; double &ans = dp[x]; if(!x) {vis[x] = 1; return ans = 0.0; } ans = 2000.0; for(int i = 0; i < 2*n; i++) if(x&(1<<i)) for(int j = i+1; j < 2*n; j++) if(x&(1<<j)) { ans = min(ans, dfs(x^(1<<i)^(1<<j))+f[i][j]); } vis[x] = 1; return ans; } int main () { int k = 0; while(scanf("%d",&n), n) { for(int i = 0; i < 2*n; i++) scanf("%s %d %d", str, &x[i], &y[i]); for(int i = 0; i < 2*n; i++) for(int j = i+1; j < 2*n; j++) f[i][j] = sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); int all = ((1<<2*n)-1); memset(vis,0,sizeof(vis)); printf("Case %d: %.2lf\n",++k, dfs(all)); } return 0; }