您的位置:首页 > 其它

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

2012-10-27 00:22 465 查看
题意:给定每个点在平面内的坐标,要求选出一些点,在这些点建立加油站,使得总花费最少(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: