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"; } } }