UvaOJ10911
这个题首先要明确 1.二进制的枚举特点
2. ^ 运算符的特点
1. 二进制枚举较多见,书上的代码是这样的
递推 是由 dp[ S ] 是 0 到 log S + 1(以2 为底) 个点集合组成的最小距离。
S 表示的是 点 i ,j 的组合种类 转换成二进制表示为 S = (1<<i)+ (1<<j)
所以通过枚举 S 就 能确定 i,j 的组合是那种。
dp[s] = min(dp[s] , dist(i,j) + dp[s ^ (1<<i) ^(1<<j)]);
2. ^ 表示异或, 0^1 = 1, 1^1 = 0 , 相异为1
则 a^a = 00000
同理 S本身枚举的就是两个点的之和, s^(1<<i) 就相当于s中原有的(1<<i) 再异或一个(1<<i) 那就说明去除了这个点,同理有异或(1<<j),有去除了j这个点。剩余的s表示的就是 剩下的点的集合了。那么dp[s] 就是剩下点集合的最小距离和。
for(s = 1;s< (1<<n );s++) { dp[s] = INF; for(i = 0;i<n;i++) if(s & (1<<i))break; for(j=i+1;j<n;j++) if(s & (1<<j)) { dp[s] = min(dp[s] ,dist(i,j) + dp[s ^ (1<<i) ^(1<<j)]); } }
#include<stdio.h> #include<string.h> #include<math.h> #define min(a,b) a<b?a:b #define INF 1<<30 int na[20][2]; double dp[100000]; double dist(int i,int j) { return sqrt( (na[i][0]-na[j][0])*(na[i][0]-na[j][0]) + (na[i][1]-na[j][1])*(na[i][1]-na[j][1])); } int main() { int n,s; int i,j,count = 1; char a[100]; while(scanf("%d",&n)) { getchar(); if(n== 0)break; for( i = 0;i< 2*n ;i++) { scanf("%s %d %d",&a,&na[i][0],&na[i][1]); } n= 2*n; dp[0] = 0; for(s = 1;s< (1<<n );s++) { dp[s] = INF; for(i = 0;i<n;i++) if(s & (1<<i))break; for(j=i+1;j<n;j++) if(s & (1<<j)) { dp[s] = min(dp[s] ,dist(i,j) + dp[s ^ (1<<i) ^(1<<j)]); } } printf("Case %d: %.2f\n",count++,dp[ (1<<n) - 1 ]); } return 0; }
http://www.cnblogs.com/pangblog/archive/2013/09/21/3331303.html
这位大神用的是深搜 感觉也不错!