hdu 4435(第37届ACM/ICPC天津赛区现场赛E题)

题意:给定每个点在平面内的坐标,要求选出一些点,在这些点建立加油站,使得总花费最少(1号点必须建立加油站)。在i点建立加油站需要花费2^i。建立加油站要求能使得汽车从1点开始走遍全图所有的点并回到1点,途中汽车加油次数不限,每个加油站的使用次数不限,但是汽车油箱有上限d(加满油可以跑距离d)。

分析:突破口在于在i号点建立加油站的费用为2^i,这样特殊的花费会使得我们有一个贪心的规律,就是尽量不在号比较大的点建加油站,如果在n号点建立加油站的费用会大于在除n以外的所有点都建加油站的总费用。所以我们可以先尝试把除n以外的所有点建立加油站,观察是否满足要求。若满足则说明我们必然不会在n点建立加油站,若不满足我们就一定要在n点建加油站。若需要建,我们就建,然后就不用再考虑n点了,在确定了n点之后,我们用同样的方法来观察n-1号点是否需要建立加油站,即将1~n-2号点都建立加油站,观察是否满足要求。以此类推,可以推出所有点的情况。

接下来我们需要解决对于一种给定的加油站建立情况,我们如何判断它是否满足题中的travel around的要求。分为两部判断,1.判断所有加油站是否可达(从1号点开始广搜,若到当前点距离<=d则入队)。2.判断其余点是否可达(刚才的广搜过程可以顺便标出每个点到最近的加油站的距离,要求能从加油站到该点并返回加油站,所以点到加油站的距离必须小于等于d/2)。若满足这两点必然符合要求,否则不符合要求。

View Code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

#define maxn 150
#define inf 0x3f3f3f3f

struct Point
{
    int x, y;
} point[maxn];

int n, d;
int map[maxn][maxn];
bool isstation[maxn];
int q[maxn];
int dist[maxn];
bool vis[maxn];

void input()
{
    for (int i = 0; i < n; i++)
        scanf("%d%d", &point[i].x, &point[i].y);
}

void make()
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            map[i][j] = ceil(
                    sqrt(
                            (point[i].x - point[j].x)
                                    * (point[i].x - point[j].x)
                                    + (point[i].y - point[j].y)
                                            * (point[i].y - point[j].y)));
}

bool ok()
{
    int front, rear;

    memset(vis, 0, sizeof(vis));
    for (int i = 0; i < n; i++)
        if (!isstation[i])
            dist[i] = inf;
        else
            dist[i] = 0;
    front = rear = 0;
    q[rear++] = 0;
    vis[0] = true;
    dist[0] = 0;
    while (front != rear)
    {
        int u = q[front++];
        for (int i = 0; i < n; i++)
            if (!vis[i]&& map[u][i] <= d)
            {
                dist[i] = min(dist[i], dist[u] + map[u][i]);
                if (isstation[i])
                {
                    vis[i] = true;
                    q[rear++] = i;
                }
            }
    }
    for (int i = 0; i < n; i++)
        if (isstation[i] && !vis[i])
            return false;
        else if (!isstation[i] && dist[i] * 2 > d)
            return false;
    return true;
}

void work()
{
    for (int i = 0; i < n; i++)
        isstation[i] = true;
    if (!ok())
    {
        printf("-1\n");
        return;
    }
    for (int i = n - 1; i >= 1; i--)
    {
        isstation[i] = false;
        if (ok())
            continue;
        else
            isstation[i] = true;
    }
    int i = n - 1;
    while (!isstation[i])
        i--;
    for (; i >= 0; i--)
        if (isstation[i])
            putchar('1');
        else
            putchar('0');
    putchar('\n');
}

int main()
{
    //freopen("t.txt", "r", stdin);
    while (~scanf("%d%d", &n, &d))
    {
        input();
        make();
        work();
    }
    return 0;
}
posted @ 2012-10-27 00:22  金海峰  阅读(...)  评论(... 编辑 收藏