JDOJ1100: Fix

题目大意

给你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;
}

猜你喜欢

转载自www.cnblogs.com/tyner/p/11617129.html