Fix

description

给定\(n\)个点,有若干个是初始固定的.一个点是固定的,当且仅当它初始固定或与至少两个固定点间连边.连接一条边的代价为此边长,求将所有点固定的最小代价.

solution

根据该数据规模,不难看出是状压题.我们先确定状态,这里规定状态中\(1\)为已固定的点,那么可以从小到大枚举状态,利用刷表法,直接贪心转移即可.

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define next MabLcdG
#define mod 1
#define debug puts("mlg")
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writesp(ll x);
inline void writeln(ll x);
inline double Sqrt(double x){
	double l=0,r=100000000.0;
	while(l+0.0000000000001<r){
		double mid=(l+r)/2;
		if(mid*mid<x) l=mid+0.0000000000001;
		else r=mid;
	}
	return l;
} 
ll n;
double f[(1<<19)];
ll tot;
struct node{
	ll x,y;
	bool check;
	inline void init(){
		x=read(),y=read();check=read();
	}
}v[20];
inline double calc(ll i,ll j){
	return  sqrt(1.0*(v[i].x-v[j].x)*(v[i].x-v[j].x)+1.0*(v[i].y-v[j].y)*(v[i].y-v[j].y));
}
struct Dode{
	double dis;
	ll p;
	inline void Init(ll i,ll j){
		dis=calc(i,j);p=j;
	}
	bool operator <(Dode X)const{return dis<X.dis;}
}c[20][20];
ll h;
int main(){	
	while(n=read()){
		h=0;tot=0;
		for(R ll i=1;i<=n;i++) v[i].init(),tot+=(v[i].check?(1<<i-1):0),h+=(v[i].check?1:0);
		for(R ll i=1;i<=n;i++){
			for(R ll j=1;j<=n;j++) c[i][j].Init(i,j);
			sort(c[i]+1,c[i]+n+1);
		}
		if(h==n){
			puts("0.000000");
			continue;
		}
		if(h<2){
			puts("No Solution");
			continue;
		}
		memset(f,127,sizeof f);
		double Maxn=f[0];f[tot]=0;
		for(R ll i=tot;i<(1<<n);i++){
			if(f[i]==Maxn) continue;
			for(R ll j=1;j<=n;j++){
				if((i&(1<<j-1))) continue;
				ll cnt=0;double dis=0;
				for(R ll k=1;k<=n;k++){
					if((i&(1<<c[j][k].p-1))) ++cnt,dis+=c[j][k].dis;
//					if(cnt==2)printf("%.6lfa\n",dis);
					if(cnt==2){
						f[i+(1<<(j-1))]=min(f[i+(1<<(j-1))],f[i]+dis);
						break;
					}
				}
			}
		}
		printf("%.6lf\n",f[(1<<n)-1]);
		
	}
	
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}
posted @ 2020-08-10 16:43  月落乌啼算钱  阅读(228)  评论(0)    收藏  举报