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
这位大神用的是深搜 感觉也不错!