POJ 2267 From Dusk till Dawn or: Vladimir the Vampire(最短路变形)

题意:

有一个吸血鬼要旅游, 他只能在晚上6点到第二天凌晨6点行动(18:00 ~ 6:00), 然后每天中午12点要喝1L的血(12:00), 现有m条火车的发车时间行程时间, 问他从a到达b需要喝多少升的血。

分析:

根据发车时间和题意, 可以把发车时间 < 18的排除掉, 然后行程时间 > 6的排除掉, 我们可以把一天看成30小时, 加起来大于30的都排除掉。

然后以血量为花费进行最短路, 如果能在同一天换乘的话, 血量花费为0, 否则为1。

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a; i < b; i++)
#define _rep(i,a,b) for(int i = a; i <= b; i++)
const int maxn = 107;
const int inf = 1e9;
struct edge{
    int to, st, end_time;
    edge(int _to,int _st,int _end_time): to(_to) ,st(_st), end_time(_end_time){}
};
struct node{
    int to, arr_time; //到达城市, 到达时间
    node(int _to, int _arr_time): to(_to) , arr_time(_arr_time){}
};
vector<edge> G[maxn];
map<string , int> id;
int city_cnt, m;

void init(){
    for(int i = 0; i < maxn; i++) G[i].clear();
    id.clear();
    city_cnt = 0;
}
void s2i(string s){//把城市名称映射成数字
    if(!id.count(s)) id[s] = city_cnt++;
}

int spfa(int from, int to){
    int dis[maxn][30 + 7]; //dis[i][j]代表在j点到达i城市需要最少血量
    bool vis[maxn][30 + 7];//代表[i][j](j点到达i城市需要最少血量)在不在队列中
    rep(i,0,city_cnt) _rep(j,18,30) dis[i][j] = inf;
    memset(vis, 0 , sizeof(vis));
    queue<node> q;
    _rep(i,18,30){
        vis[from][i] = 1;
        dis[from][i] = 0;
        q.push(node(from,i));
    }
    while(!q.empty()){
        node f = q.front();
        int u = f.to, t = f.arr_time;
        rep(i,0,G[u].size()){
            int st_time = G[u][i].st, v = G[u][i].to, ed_time = G[u][i].end_time;
            if(t <= st_time){//在同一天可以赶上这趟火车

                if(dis[v][ed_time] > dis[u][t]){ //不需要带1L血
                    dis[v][ed_time] = dis[u][t];
                    if(!vis[v][ed_time]){
                        vis[v][ed_time] = 1;
//                        printf("same day\n");
                        q.push(node(v,ed_time));
                    }
                }
            }
            else //同一天赶不上这趟火车, 需要带上1L血
            {
                if(dis[v][ed_time] > dis[u][t] + 1) //这个+1就是1L血
                {
                    dis[v][ed_time] = dis[u][t] + 1;
                    if(!vis[v][ed_time]){
                        vis[v][ed_time] = 1;
                        q.push(node(v, ed_time));
                    }
                }
            }
        }
        vis[u][t] = 0;
        q.pop();
    }
    int min_dis = inf;
    _rep(i,18,30){//枚举目标城市每个到达时间的最少血量, 选最少的一个为答案
        min_dis = min(min_dis, dis[to][i]);
    }
    return min_dis;
}
int main(){
    int T, kase = 1;
    cin >> T;
    while(T--){
        init();
        string from, to;
        cin >> m;
        rep(i,0,m){
            string u , v;
            int st, dur;
            cin >> u >> v >> st >> dur;
            s2i(u),s2i(v);
            if(st <= 6) st += 24;//如果起始时间小于6, 那么当24 + st小时算
            if(!(st >= 18 && st + dur <= 30)) continue; //总时间小于30, 起始时间大于18都是符合题意的。
            G[id[u]].push_back(edge(id[v],st, st + dur));
        }
        cin >> from >> to;
        s2i(from),s2i(to);
        cout << "Test Case " << kase++ <<".\n";
        int blood = spfa(id[from], id[to]);
        if(blood == inf){
            cout << "There is no route Vladimir can take.\n";
        }else{
            cout << "Vladimir needs " << blood << " litre(s) of blood.\n";
        }
    }
}

 

posted @ 2018-01-24 14:44  Neord  阅读(175)  评论(0编辑  收藏  举报