题目大意
给你n个点,其中一些点是固定的,然后还有一些没有固定的,然后问你固定所有点所用的线段的最小长度是多少。
所谓固定,就是形如三角形的情况,就是两个固定的点向一个未固定的点连两条边,就能把未固定的点固定。
数据范围
1 <= n <= 18
分析
感觉这简单的状压长得跟搜索似得
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string.h>
using namespace std;
const int MAX = 19;
const int INF = 2147000047;
inline int read() {
char ch = getchar(); int f = 1, x = 0;
while(ch<'0' || ch>'9') {if(ch=='-') f = -1; ch = getchar();}
while(ch>='0' && ch<='9') {x = x*10+ch-'0'; ch = getchar();}
return x*f;
}
int n, sta, is;
double f[1<<MAX];
struct node{
double x, y;
}arr[MAX];
double juli(double x1, double y1, double x2, double y2) {
return sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}
double min_juli(int s, int j) {//当前状态s,新插入点j,返回插入后状态s`的f
double min1 = INF, min2 = INF, tmp;
for(int i = 1; i <= n; i++)
if(s&(1<<(i-1))) {
tmp = juli(arr[i].x, arr[i].y, arr[j].x, arr[j].y);
if(tmp <= min1) min2 = min1, min1 = tmp;
else if(tmp < min2) min2 = tmp;
}
return min1+min2;//暂不考虑 不存在min
}
void pre() {
memset(arr, 0, sizeof(arr));
for(int i = 1; i < (1<<n); i++) f[i] = INF;
sta = 0;
for(int i = 1; i <= n; i++) {
arr[i].x = read(), arr[i].y = read(), is = read();
sta |= (is<<(i-1));
}
f[sta] = 0;
}
void solve() {
int tmp;
for(int i = sta; i < (1<<n); i++) if((i&sta) == sta) {
tmp = (~i & ((1<<n)-1));
// printf("i: %d, 取0:%d\n", i, tmp);
for(int j = 1; j <= n; j++) if(tmp&(1<<(j-1))) {
// printf("j: %d,插入之后: %d\n", j, i|(1<<(j-1)));
f[i|(1<<(j-1))] = min(f[i|(1<<(j-1))], f[i] + min_juli(i, j));
}
}
if(f[(1<<n)-1] >= INF) printf("No Solution\n");
else printf("%.6f\n", f[(1<<n)-1]);
}
int main() {
while(scanf("%d",&n) && n) {
pre();
solve();
}
return 0;
}