题目出自《算法竞赛入门经典》动态规划那一章
大意:空间里有n个点P0,P1,…,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点恰好在一个点对中。所有点对中两点的距离之和应尽量小。
OJ 版本:10911 - Forming Quiz Teams
书中的解法不好,原因是,计算了大量无用的状态
所以使用记忆化搜索会更快一些
#include<cstdio>
#include<cassert>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cfloat>
using namespace std;
const int maxlen=16;
struct Point
{
int x;
int y;
void set(int xx,int yy)
{
x=xx;
y=yy;
}
};
inline double getdist(const Point &p1,const Point&p2)
{
double dx=p1.x-p2.x;
double dy=p1.y-p2.y;
double d=sqrt(dx*dx+dy*dy);
return d;
}
Point points[maxlen];
double dist[maxlen][maxlen];
char name[80];
const int max_state_size=((1<<16));
char visit[max_state_size];
double minlen[max_state_size];
double subsearch(int mask,int start)
{
if(visit[mask])
{
return minlen[mask];
}
double temp;
double tempmin=DBL_MAX;
int i;
for(i=start;i>=0;i--)
{
if(mask&(1<<i))
{
break;
}
}
for(int j=i-1;j>=0;j--)
{
if(mask&(1<<j))
{
temp=dist[i][j]+subsearch(mask^(1<<i)^(1<<j),i-1);
tempmin=min(tempmin,temp);
}
}
minlen[mask]=tempmin;
visit[mask]=1;
return tempmin;
}
double search(int len)
{
memset(visit,0,sizeof(visit));
visit[0]=1;
minlen[0]=0;
int state=(1<<len)-1;
return subsearch(state,len-1);
}
int main()
{
int case_i=0;
int n;
while(cin>>n)
{
if(n==0)
{
break;
}
n=n*2;
case_i++;
for(int i=0;i<n;i++)
{
scanf("%s %d %d",name,&points[i].x,&points[i].y);
}
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
double t=getdist(points[i],points[j]);
dist[i][j]=t;
dist[j][i]=t;
}
}
printf("Case %d: %.2lf\n",case_i,search(n));
}
system("pause");
return 0;
}
参考:
http://www.cppblog.com/rakerichard/archive/2010/02/11/107696.html
http://blog.csdn.net/to_be_better/article/details/50772763
http://blog.csdn.net/lhshaoren/article/details/7526480