題目鏈接: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;
}