题意:
一个人在12:00 ~ 12 :59 这个时间段,观察了一个汽车站台的公共汽车的来往情况,并且记录了每一辆车的到站时间。这些记录的车满足下面的情况:
在12:00 ~12:59 期间,同一线路上的公共汽车以相同的时间间隔到站。
1. 每条公共汽车线路至少有两辆车到达本站
2. 来自不同线路的公共汽车可以同时到达本站
3. 不同公共汽车线路的车首次到达本站的时间和到站的时间间隔都有可能相同
求最小的汽车路线数。
思路:
1. 首先统计出所有可能的公共汽车时刻方案,存放在数组中,为了方便后面的剪枝发挥效果,对其在 1 小时内的停站次数从大到小排序;
2. 下面 DFS 的过程比较出彩,不同于传统的深搜,这次是对于等差数列的元素成组消去,然后再还原;
3. 题目中给出了最大的路线数为 17,可以以此为依据最大剪枝。对于向后选择路线时,对于到站次数的从大到小进行一个最小的预估,如果超出,则剪枝;
#include <iostream>
#include <algorithm>
using namespace std;
struct ST {
int arrive, interval, times;
bool operator < (const ST& other) const { return times > other.times; }
} route[1800];
int N, hash[60], routecnt, ans;
bool checkroute(int s, int delta) {
for (int i = s; i < 60; i += delta) {
if (!hash[i])
return false;
}
return true;
}
void dfs(int k, int sum) {
if (sum >= ans)
return;
if (N == 0) {
ans = min(ans, sum);
return;
}
for (int i = k; i < routecnt; i++) {
if (route[i].times > N)
continue;
if (sum + N/route[i].times >= ans)
return;
if (!checkroute(route[i].arrive, route[i].interval))
continue;
for (int j = route[i].arrive; j < 60; j += route[i].interval)
N -= 1, hash[j] -= 1;
dfs(i, sum + 1);
for (int j = route[i].arrive; j < 60; j += route[i].interval)
N += 1, hash[j] += 1;
}
}
int main() {
scanf("%d", &N);
memset(hash, 0, sizeof(hash));
for (int i = 0; i < N; i++) {
int x;
scanf("%d", &x);
hash[x] += 1;
}
routecnt = 0;
for (int i = 0; i < 30; i++) {
for (int j = i + 1; j + i < 60; j++) {
if (checkroute(i, j)) {
route[routecnt].arrive = i;
route[routecnt].interval = j;
route[routecnt].times = (59-i)/j + 1;
routecnt += 1;
}
}
}
sort(route, route + routecnt);
ans = 17;
dfs(0, 0);
printf("%d\n", ans);
return 0;
}