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;

}

你可能感兴趣的:(ICPC)