题意:给定每个点在平面内的坐标,要求选出一些点,在这些点建立加油站,使得总花费最少(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; }