题意:平面上给n个点的坐标,两个点之间的距离是它们欧几里德距离向上取整。你有一两车子,加满油能跑d的距离,现在你需要在其中一些点上建加油站,使你可以从点1出发访问所有的点最后回到点1。在点i建加油站的费用是2^(i-1),若有解,输出最小费用的二进制表示,若无解输出-1。
思路:贪心。先在所有的点上建加油站,如果不能跑完则无解。在有解的情况下,从n到1枚举点去掉加油站,如果还能跑完就把这个加油站去掉。这样贪心成立的依据是1+2+4+...+2^(n-1)<2^n。判断能不能跑完用bfs,对于有加油站的点,离上一个有加油站的点距离<=d即可;对于没有加油站的点,需要离上一个有加油站的点的距离*2<=d。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <vector>
#include <queue>
using namespace std;
int dis[130][130];
int x[130];
int y[130];
bool ans[130]; //有无加油站直接可以作为二进制费用输出
bool vis[130];
int n,d;
bool bfs(){
memset(vis,0,sizeof(vis));
queue<int> que; que.push(1);
vis[1]=1;
while(!que.empty()){
int cur=que.front(); que.pop();
for(int i=1;i<=n;i++){
if(i==cur)continue;
if(vis[i])continue;
if(ans[i]){
if(dis[cur][i]<=d){
que.push(i);
vis[i]=1;
}
}else{
if(dis[cur][i]*2<=d){
vis[i]=1;
}
}
}
}
for(int i=1;i<=n;i++){
if(!vis[i])return 0;
}
return 1;
}
int main(){
while(cin>>n>>d){
for(int i=1;i<=n;i++){
ans[i]=1;
scanf("%d%d",&x[i],&y[i]);
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
dis[i][j]=dis[j][i] = ceil( sqrt( (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]) ) );
}
}
if(n==1){ //特判只有一个点
cout<<0<<endl;
continue;
}
if(!bfs()){
cout<<"-1"<<endl;
continue;
}
for(int i=n;i>1;i--){ //贪心去掉加油站
ans[i]=0;
bool flag=bfs();
if(!flag)ans[i]=1;
}
int i;
for(i=n;i>=1;i--){ //去前导0
if(ans[i])break;
}
for(;i>=1;i--){
cout<<ans[i];
}
cout<<endl;
}
return 0;
}