题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3362
题目大意:给出n(n<=18)个点的坐标,某些点固定了,某些点没固定,要求加一些边使得没固定的点变成固定,求最小花费。
思路:n比较小可用状压DP,从所给的起始状态开始DP,每个状态里面都枚举一个未固定的点然后通过找两个已经固定的点更新另一个状态,dp保存最优值即可。
Code:
/* W w w mm mm 222222222 7777777777777 */
/* W w w w m m m m 222 22 7777 */
/* w w w w m m m m 22 777 */
/* w w w w m m m m 22 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* w w w w m m m m 222 77 */
/* ww ww m mm m 222222222222222 77 */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n;
const int N=20;
const int maxn=300005;
double dist[20];
int st,en;
struct Point
{
double x,y;
int c;
}a[N];
double dp[maxn];
void init()
{
for(int i=0;i<(1<<n);i++)
{
dp[i]=-1;
}
}
void debug()
{
for(int i=st;i<(1<<n);i++)
{
printf("dp[%d]=%f\n",i,dp[i]);
}
}
void debug_dist()
{
for(int i=1;i<=n;i++)
{
printf("dist[%d]=%f\n",i,dist[i]);
}
}
double dis(int i,int j)
{
return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)
+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
void solve()
{
st=0;
for(int i=1;i<=n;i++)
{
if(a[i].c)
{
st+=1<<(i-1);
}
}
dp[st]=0;
//printf("st=%d\n",st);
en=(1<<n)-1;
for(int i=st;i<=en;i++)
{
if(dp[i]<0)
{
continue;
}
for(int j=1;j<=n;j++)
{
if(!(i&(1<<(j-1))))
{
//printf("i=%d j=%d\n",i,j);
int cnt=0;
for(int p=1;p<=n;p++)
{
if((i&(1<<(p-1))))
{
//printf("p=%d\n",p);
dist[cnt++]=dis(j,p);
//printf("%f\n",dis(j,p));
}
}
if(cnt<2)continue;
//debug_dist();
sort(dist,dist+cnt);
int S=i+(1<<(j-1));
if(dp[S]<0)
{
dp[S]=dp[i]+dist[0]+dist[1];
}
else
{
dp[S]=min(dp[S],dp[i]+dist[0]+dist[1]);
}
//debug_dist();
}
}
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("test.in","r",stdin);
#endif
while(~scanf("%d",&n))
{
if(!n)break;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%d",&a[i].x,&a[i].y,&a[i].c);
}
init();
solve();
//debug();
if(dp[(1<<n)-1]<0)
{
printf("No Solution\n");
}
else
{
printf("%.6f\n",dp[(1<<n)-1]);
}
}
return 0;
}