2012天津E题

时间:2021-08-21 19:57:34

给我们n个坐标点和一个距离d,表示车开m米就没油了。

然后要选几个点建立油站,使得能够从1出发遍历所有的点,然后回到1。  并且规定1这个点必须有油站,在第i个点建立油站的费用是 2^(i-1)

因为费用的特殊性质,如果最大的点能够不建立,那么肯定是不建的。 所以首先在所有的点建立油站,看是否可以遍历所有的点,然后依次从大到小枚举点,看是否可以不建立油站。

但是卡在如何判断是否能够遍历所有的点上。

首先判断,所有的油站距离最近的油站的距离不能超过d,  如果超过就不能到达,而且也不能通过没有油站的点中转

然后,不是油站的点距离最近的油站的距离不能超过d/2 ,这个很显然,如果超过d/2,那么从油站到达这个点,就没办法回去了。

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <math.h>
using namespace std;
/*
花费是2^(i-1) 这个很特殊
如何高效得判断是否能经过所有的点然后回家?
*/
const int INF = <<;
const int N = + ;
struct Point
{
int x,y;
double dist(const Point &rhs)
{
return sqrt( (x-rhs.x)*(x-rhs.x)+(y-rhs.y)*(y-rhs.y) );
}
}a[N];
int n,d;
int dist[N][N];
int sta[N];
bool vis[N];
int cnt1,cnt2;
bool bfs()
{
memset(vis,,sizeof(vis));
int tmp = ;
for(int i=;i<=n;++i)
tmp += sta[i];
cnt1 = ;
cnt2 = ;
vis[] = true;
queue<int> q;
q.push();
while(!q.empty())
{
int u = q.front();q.pop();
for(int i=;i<=n;++i)
{
if(!sta[i]) continue;
if(!vis[i] && dist[u][i]<=d)
{
q.push(i);
cnt1++;
vis[i] = true;
}
}
}
for(int i=;i<=n;++i)
if(sta[i]) q.push(i);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i=;i<=n;++i)
{
if(sta[i]) continue;
if(!vis[i] && dist[u][i]*<=d)
{
vis[i] = true;
cnt2++;
}
}
}
if(cnt1==tmp && cnt2==n-tmp) return true; return false;
}
int main()
{
//freopen("d:/in.txt","r",stdin);
while(scanf("%d%d",&n,&d)!=EOF)
{
for(int i=;i<=n;++i)
{
scanf("%d%d",&a[i].x,&a[i].y);
sta[i] = true;
}
for(int i=;i<=n;++i)
{
for(int j=;j<=n;++j)
dist[i][j] = dist[j][i] = (int)ceil(a[i].dist(a[j]));
}
if(bfs())
{ for(int i=n;i>=;--i)
{
sta[i] = false;
if(!bfs())
sta[i] = true;
}
while(sta[n]==) n--;
for(int i=n;i>=;--i)
printf("%d",sta[i]);
puts("");
}
else
puts("-1");
}
return ;
}