#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=17;
/*这里参考大佬的代码,去掉初始位进行二进制枚举*/
int n,m,maxs,lim,cnt;
int x[maxn],y[maxn],c[maxn];
int dp[1<<maxn];///某状态下的最少使用教练
int ds[1<<maxn];///某状态下的最少路程花费
int dpp[1<<maxn][maxn];///状态s下,当前在i点的最小路程花费
int dd[1<<maxn];///解决状态s并返回起点的最小路程花费
int bin[1<<maxn];
int state[1<<maxn],dis[maxn][maxn];
bool isok(int st){///位枚举
int sum=0,idx=1;
while(st){
if(st&1) sum+=c[idx];
st>>=1;
idx++;
}
if(sum>m) return false;
return true;
}
void Init(){
for(int i=0;i<16;i++)
bin[1<<i]=i+1;
}
void makesta(){///树状数组处理
cnt=0;
for(int i=0;i<1<<(n-1);i++){
int tmp=i,tot=0;
while(tmp){
int x=tmp&(-tmp);
tot+=c[bin[x]];
tmp-=x;
}
if(tot<=m)state[++cnt]=i;
}
}
void get_dis(){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dis[i][j]=ceil(sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));
}
void get_dd(){
for(int i=1;i<n;i++) dpp[1<<(i-1)][i-1]=dis[0][i];
for(int i=0;i<lim;i++){
for(int j=0;j<n-1;j++){
if(!(i&(1<<j))) continue;
dd[i]=min(dd[i],dpp[i][j]+dis[j+1][0]);
for(int k=0;k<n-1;k++){
if(i&(1<<k)) continue;
dpp[i|(1<<k)][k]=min(dpp[i|(1<<k)][k],dpp[i][j]+dis[j+1][k+1]);
}
}
}
}
int main(){
Init();
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
get_dis();
maxs=0;
for(int i=0;i<n;i++){
scanf("%d",&c[i]);
maxs=max(maxs,c[i]);
}
if(maxs>m){
printf("-1 -1\n");
continue;
}
lim=1<<(n-1);
//makesta();
cnt=0;
for(int i=0;i<lim;i++) if(isok(i)) state[++cnt]=i;
memset(dp,inf,sizeof(dp));
memset(ds,inf,sizeof(ds));
memset(dpp,inf,sizeof(dpp));
memset(dd,inf,sizeof(dd));
get_dd();
dp[0]=ds[0]=0;
for(int i=0;i<lim;i++)
for(int j=1;j<=cnt;j++){
if(i&state[j]) continue;
dp[i|state[j]]=min(dp[i|state[j]],dp[i]+1);
ds[i|state[j]]=min(ds[i|state[j]],ds[i]+dd[state[j]]);
}
if(dp[lim-1]==inf) printf("-1 ");
else printf("%d ",dp[lim-1]);
if(ds[lim-1]==inf) printf("-1\n");
else printf("%d\n",ds[lim-1]);
}
return 0;
}
#include<algorithm>
#include<iostream>
#include<string.h>
#include<sstream>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<string>
#include<time.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
int n,m,cnt,ans1,ans2,lim;
int x[20],y[20],c[20];
int state[1<<17];//存可行状态
int dp[1<<17],dis[20][20];//dp处理最少的裁判数
int dpp[20][1<<17],mind[1<<17];//dpp[i][j]表示当前在i点。访问状态为j时的最小距离。
//clock_t st,ed; //mind[i]表示完成访问状态i所走的最少路程
//double dur;
void debug(){
cout<<"***"<<endl;
for(int i=0;i<cnt;i++) cout<<state[i]<<endl;cout<<"***"<<endl;
}
bool isok(int st)//判断一个裁判的可行状态。抽象为一个物品。
{
int i=0,sum=0;
while(st)
{
if(st&1)
sum+=c[i];
st>>=1;
i++;
}
if(sum<=m)
return true;
else
return false;
}
void getDist()//求距离
{
int i,j,xx,yy;
for(i=0;i<n;i++)
{
dis[i][i]=0;
for(j=i+1;j<n;j++)
{
xx=x[j]-x[i];
yy=y[j]-y[i];
dis[i][j]=dis[j][i]=ceil(sqrt((double)(xx*xx+yy*yy)));
}
}
}
void TSP()//典型的单旅行商问题
{
int s,j,ns;
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(s=0;s<lim;s++)
{
if(dp[s]==INF)
continue;
for(j=0;j<cnt;j++)
{
if(s&state[j])///有重叠
continue;
ns=s|state[j];
dp[ns]=min(dp[ns],dp[s]+1);
}
}
ans1=dp[lim-1];
}
void MTSP()//多旅行商
{
int i,j,k,s,ns;
getDist();
memset(dpp,0x3f,sizeof dpp);
memset(mind,0x3f,sizeof mind);
dpp[0][1]=0;//0必须为起点
for(i=0;i<cnt;i++)
{
s=state[i];
for(j=0;j<n;j++)
{
if(s&(1<<j)&&dpp[j][s]!=INF)///枚举最后一步伐
{
mind[s]=min(mind[s],dpp[j][s]+dis[j][0]);//把一个裁判完成访问状态再回到0点抽象为一个物品
for(k=0;k<n;k++)
{
if(s&(1<<k))
continue;
ns=s|(1<<k);//ns状态不一定有效
dpp[k][ns]=min(dpp[k][ns],dpp[j][s]+dis[j][k]);
}
}
}
}
for(s=1;s<lim;s++)///枚举s的子集的划分,ns和s-ns
{
if(s&1)
{
for(ns=(s-1)&s;ns;ns=(ns-1)&s)
mind[s]=min(mind[s],mind[ns|1]+mind[(s-ns)|1]);
}
}
///这是我的DP方法极限数据18s。。汗。。
ans2=mind[lim-1];
}
int main()
{
int i,ma;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++)
scanf("%d%d",&x[i],&y[i]);
ma=0;
for(i=0;i<n;i++)
{
scanf("%d",&c[i]);
ma=max(ma,c[i]);
}
if(ma>m)
{
printf("-1 -1\n");
continue;
}
cnt=0,lim=1<<n;
for(i=0;i<lim;i++)
if(isok(i))
state[cnt++]=i;debug();
TSP();
MTSP();
printf("%d %d\n",ans1,ans2);
}
return 0;
}