HDU 4435 charge-station

题意:给出N个点及其坐标,一个人开车从第一个点开始,要遍历完所有城市,同时返回第一个城市。汽车加一次油,有最大的行驶距离D。所以,要在一些城市建加油站才能完成上面的任务。

对于给出的的第i个城市,建加油站的费用为2 ^ (i-1).问,如何建加油站,让花费最小,同时可以完成城市的遍历。

思路:对于花费,我们可以看到一个有趣的性质:在前i-1个城市建加油站的费用比第i个城市建加油站的还要小。

那么,如果在前i个城市建加油站能满足要求,就不需要在第i个城市建加油站。这样,我们就能够从最后一个城市开始,贪心枚举能不建加油站的城市。

这样,这个问题就变成了判定性问题,给定建加油站的方案,判断能否遍历完所有的城市并返回。

我们可以用搜索完成这个判定性问题。

这个图中,一共有两种点,有加油站,没加油站。对于有加油站的点,从某个城市到达,那一定可以回到该城市。

而对于没有加油站的城市,那他的油要保证能够往返。即,该点到最近的加油站的距离小于等于最大行驶距离的二倍。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;

const int MAX = 200;
int N,D;
int d[MAX][MAX];
int dis[MAX];
double x[MAX],y[MAX];
bool vis[MAX];
bool build[MAX];
int que[MAX],front,tail;

bool bfs()
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    for(int i = 0 ; i < N; ++i)
        if(build[i]) dis[i] = 0;
    front = tail = 0;
    que[tail++] = 0;
    vis[0] = true;
    while(front < tail){
        int u = que[front++];
        for(int i = 0; i < N; ++i){
            if(!vis[i] && d[u][i] <= D){
                    dis[i] = min(dis[i],d[u][i]);
                if(build[i]){
                    vis[i] = true;
                    que[tail++] = i;
                }
            }
        }
    }
    for(int i = 0; i < N; ++i){
        if(build[i] && !vis[i])
                return false;
        else if(!build[i] && 2 * dis[i] > D)
                return false;
        }
    return true;
}

int main(void)
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d %d", &N,&D) != EOF){
        for(int i = 0; i < N; ++i)
            scanf("%lf %lf", &x[i], &y[i]);
        for(int i = 0; i < N; ++i){
            for(int j =0; j < i; ++j)
                d[i][j] = d[j][i]= ceil(sqrt((x[i] - x[j]) * (x[i] - x[j])
                                             + (y[i] - y[j]) * (y[i] - y[j])));
            d[i][i] = 0;
        }
        fill(build,build + MAX,true);
        if(!bfs()){
            puts("-1");
            continue;
        }
        else{
            for(int i = N - 1; i > 0; --i){
                build[i] = false;
                if(!bfs()) build[i] = true;
            }
            int i = N-1;
            while(!build[i]) i--;
            for(; i >= 0; --i)
                printf("%d",build[i]);
            puts("");
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值