1. 程式人生 > >POJ 1167 (DFS·剪枝·公交時刻表)

POJ 1167 (DFS·剪枝·公交時刻表)

題意  你記錄了[0, 59]這個時間段內到達你所在站牌的所有公交的到這個站牌的時間  對於每路公交

1. 同一路公交的到站時間間隔是相同的

2. 每路公交在這個時間段至少到達兩次

3. 最多有17路公交

4. 兩個不同路的公交的第一次到站時間和到站時間間隔都可能是相同滴

5. 你在這個時間段內的記錄是完整的

求最少用多少路公交可以讓你的記錄合法

由於每路公交至少到站兩次  那麼第一次到站時間是肯定小於30的  而且到站時間間隔肯定要大於第一次到站的時間  那麼可以根據你的記錄生成所有可能合法的公交線路   最後dfs找出最少的公交線路  使這些線路剛好完全覆蓋你的記錄  注意dfs過程中的剪枝

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 1505;
int cnt[N], n, m, ans;

struct route //定義公交線路結構體
{
    int start, interval, times;
    route() {}
    route(int s, int i, int t): start(s), interval(i), times(t) {}
    bool operator< (const route &r) const {
        return times > r.times;
    }
} r[N];

bool ok(int time, int inter)
{
    while(time < 60)
    {
        if(!cnt[time]) return false;
        time += inter;
    }
    return true;
}

//從第k條線路開始匹配 當前已經匹配num個記錄  用了sum個公交線路
void dfs(int k, int num, int sum)
{
    if(num == n)
    {
        if(sum < ans) ans = sum;
        return;
    }

    for(int i = k; i < m; ++i)
    {
        if(sum + (n - num) / r[i].times >= ans) return;
        //剪枝 r是按趟數從大到小排序的  所以最少還需要(n - num) / r[i].times個線路
        if(!ok(r[i].start, r[i].interval)) continue;
        for(int j = r[i].start; j < 60; j += r[i].interval) --cnt[j];
        dfs(i, num + r[i].times, sum + 1);
        //i之前的線路之前已經搜尋過了
        for(int j = r[i].start; j < 60; j += r[i].interval) ++cnt[j]; //回溯
    }
}

int main()
{
    int t;
    while(~scanf("%d", &n))
    {
        memset(cnt, 0, sizeof(cnt));
        for(int i = 0; i < n; ++i)
            scanf("%d", &t), ++cnt[t]; //記錄每個時刻出現多少公交

        m = 0;//生成以時刻i為首班  兩班間隔時間為j的所有滿足的公交線路
        for(int i = 0; i < 30; ++i)
            for(int j = i + 1; j < 60 - i; ++j)
                if(ok(i, j)) r[m++] = route(i, j, 1 + (59 - i) / j);

        sort(r, r + m);
        ans = 17;
        dfs(0, 0, 0);
        printf("%d\n", ans);
    }
    return 0;
}
The Buses

Description

A man arrives at a bus stop at 12:00. He remains there during 12:00-12:59. The bus stop is used by a number of bus routes. The man notes the times of arriving buses. The times when buses arrive are given. 
  • Buses on the same route arrive at regular intervals from 12:00 to 12:59 throughout the entire hour. 
  • Times are given in whole minutes from 0 to 59. 
  • Each bus route stops at least 2 times. 
  • The number of bus routes in the test examples will be <=17. 
  • Buses from different routes may arrive at the same time. 
  • Several bus routes can have the same time of first arrival and/or time interval. If two bus routes have the same starting time and interval, they are distinct and are both to be presented.

Find the schedule with the fewest number of bus routes that must stop at the bus stop to satisfy the input data. For each bus route, output the starting time and the interval. 

Input

Your program is to read from standard input. The input contains a number n (n <= 300) telling how many arriving buses have been noted, followed by the arrival times in ascending order.

Output

Your program is to write to standard output. The output contains one integer, which is the fewest number of bus routes.

Sample Input

17
0 3 5 13 13 15 21 26 27 29 37 39 39 45 51 52 53

Sample Output

3

Source