思路:集合上的动态规划。
就这个题目而言,用整数表示的集合可以很好的表现除去某个元素的集合这种特点。
集合中的元素已经隐含了阶段,集合是从较小的子集逐渐枚举到较大的子集的,正符合动规的特点。
另外注意用整数表示集合,数组要开到比1<<n大。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <cmath> #include <queue> #include <algorithm> #define ll long long #define INF 1e10//2139062143 #define inf -2139062144 #define MOD 20071027 #define MAXN 20 using namespace std; int n; int x[MAXN],y[MAXN]; double dp[1000005],dis[MAXN][MAXN]; bool vis[1000005]; double distance(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double DP(int S) { if(vis[S]||!S) return dp[S]; vis[S]=true; int i; for(i=n-1; i>=0; --i) if(S&(1<<i)) break; dp[S]=INF; for(int j=i-1; j>=0; --j) if(S&(1<<j)) dp[S]=min(dp[S],dis[i][j]+DP(S^(1<<i)^(1<<j))); return dp[S]; } int main() { int kase=0; dp[0]=0; while(scanf("%d",&n)&&n) { n=n<<1; char str[25]; for(int i=0; i<n; ++i) scanf("%s%d%d",str,&x[i],&y[i]); for(int i=0; i<n; ++i) for(int j=i+1; j<n; ++j) dis[i][j]=dis[j][i]=distance(x[i],y[i],x[j],y[j]); memset(vis,0,sizeof(vis)); printf("Case %d: %.2lf\n",++kase,DP((1<<n)-1)); } return 0; }