POJ 1167 The Buses

来源:互联网 发布:形容女生的词语网络词 编辑:程序博客网 时间:2024/05/21 17:14

Name: The Buses
P_ID: POJ 1167
题目链接:http://poj.org/problem?id=1167

题意关键点:
1. 同一时刻可能有不同路线的车到达。这个要区分。
2. 每种路线的interval一定大于等于这条路线的第一辆车到达的时间。(强剪枝,因为这说明29分钟之后到的车都不可能是某条路线的第一辆车。)

题目分析:
这个题目的难点在于两个:
1. 建模
2. 剪枝

首先是建模。
一个比较明显的解决办法是dfs搜索。但是怎么建立模型比较麻烦。
我们可以基于路线建模。建一个名叫busRoute的struct,包含三个元素,begin, interval, times(这条路线中包括的车次)。建立结构数组,route[i]表示第i条路线。建立数组sumBus[i]记录第i分钟到达的车的数量。有了这些,我们可以开始读入数据并存储。

然后是剪枝。
我们首先要在route中存下所有可能包含的路线,注意,由于所有可能路线的第一辆车到达时间一定小于等于29,所以循环控制小于等于29(剪枝1)。所有可能包含的路线存储下之后,有一个很重要的剪枝工作,就是对这些所有可能的路线,按照其所包含的times从大到小进行排序(剪枝2)。如果当前已经确定的路线数量,加上假设剩下的没用过的车次都用下一个路线车次大小的路线(不一定存在)表示所需要的路线数量,就已经大于当前ans值,那么说明,这条路是死路,以后的不用做了,无用功。(类似POJ 1190)(剪枝3)

参考代码:

/** *name: The Buses *date: 2016-04-21 *note: dfs + modelling + pruning    difficult  */#include <cstdio>#include <algorithm>#include <cstdlib>#include <cstring>using namespace std;struct busRoute {    int begin;    int interval;    int times;};busRoute route[1300];int n, sumBus[1300];int tot = 0, ans = 17;bool comp(const busRoute a, const busRoute b){    return (a.times > b.times);}bool checkRoute(int a, int b){    for(int i=a; i<60; i+=b)    {        if(sumBus[i]==0)            return false;    }    return true;}//num表示目前已经确定的路线数量void dfs(int a, int num){    if(n<=0)    {        if(num < ans)            ans = num;        return;    }    for(int k=a; k<tot; ++k)    {        if(num + n/(route[k].times) >= ans) return;//剪枝3        if(checkRoute(route[k].begin, route[k].interval))        {            int temp = route[k].interval;            for (int i = route[k].begin; i < 60; i += temp)//入栈            {                sumBus[i]--;                n--;            }            dfs(k, num + 1);//深搜            for (int i = route[k].begin; i < 60; i += temp)//回溯            {                sumBus[i]++;                n++;            }        }    }}int main(){    scanf("%d", &n);    memset(sumBus, 0, sizeof(sumBus));    int bus;    for(int i=0; i<n; ++i)    {        scanf("%d", &bus);        sumBus[bus]++;    }    tot = 0;    for(int i=0; i<30; ++i)//剪枝1    {        if(sumBus[i]==0) continue;        for(int j=i+1; j<60-i; ++j)        {            if(checkRoute(i, j))            {                route[tot].begin = i;                route[tot].interval = j;                route[tot].times = (59-i)/j + 1;                tot++;            }        }    }    sort(route, route+tot, comp);//剪枝2    ans = 17;    dfs(0, 0);    printf("%d\n", ans);    return 0;}
0 0
原创粉丝点击