poj 2267 From Dusk till Dawn or: Vladimir the Vampire
有个吸血鬼要从城市 A 到城市 B, 但是吸血鬼有 3 个问题需要克服:他只能在傍晚 18:00 到凌晨 6:00 之间旅行,其他时间只能待在车站。二:他必须带一个盒子,盒子里面装的血。三:他每天中午 12 点需要喝盒子里面的 1 升血。
问题:你帮吸血鬼找到一条路径,它需要带最少的血。
输入: n :道路的条数
每条路包括:起始城市,终点城市,起始时间,所需要的时间
输出:如果能找到路径则输出最少量的血。
题目是个单源最短路径题目,最开始想用 prim 算法解决,然后开始写程序,写到中途觉得不太对了, route ( A->B ),如果存在很多条需要血量一样的道路,到底保存哪一条呢?保存起始时间最晚的,还是到达时间最早的;因为这两种情况都有可能是最优情况的候选。
后来就想的比较愚笨的方法,不就是要找一条路么?我把所有的路遍历,终归能够找到那条需要的路吧,所以我选择了深度搜索算法。
先进行预处理,把那些吸血鬼没办法走的路去掉,然后把城市用数字编号表示。吸血鬼只能在 18:00-6:00 之间进行旅行,这个时间段处理起来很麻烦,所以我把它全部加 6 ,这样子时间就变成了 0:00-12:00 ,这样子,只要到达时间 <= 出发时间就不用喝血了,否则就需要喝。
预处理完成,保存每条吸血鬼有可能走的路,按照以下数据结构。
struct {
int citys;// 起点城市
int citye;// 终点城市
int start;// 起始时间
int cost;// 路上花费的时间
}road[NUMR];NUMR 最大的路数
然后搜索到可能到的城市,保存吸血鬼的状态,按照以下数据结构
struct {
int arrive;// 到达时间
int litre;// 到达城市i 需要的血量
}blood[NUMC];//NUMC 最大的城市数
如果到达的时间晚于出发的时间,则需要+1 的血量。
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
#define NUMC 103
#define NUMR 1005
#define NUMN 35
#define INF 1000000
struct {
int citys;
int citye;
int start;
int cost;
}road[NUMR];
struct {
int arrive;
int litre;
}blood[NUMC];
char city[NUMC][NUMN];
int numR,numC,ans;//numR 表示路径的条数,numC 表示出现过的城市数
void DFS(int src,int dst)
{
if (src==dst)// 找到目的城市,则返回
{
if (blood[src].litre<ans)
ans=blood[src].litre;
return ;
}
if (blood[src].litre>=ans)// 未到目的城市,可是这条路没办法找到更优的结果,则返回
return ;
for (int i=0;i<numR;i++)// 找到以src 为起点城市的路,然后进行旅行
if (road[i].citys==src&&blood[road[i].citys].litre+1<=blood[road[i].citye].litre)
{
blood[road[i].citye].arrive=road[i].start+road[i].cost;
if (blood[road[i].citys].arrive<=road[i].start)// 到达的时间晚于出发的时间,就需要喝血了
blood[road[i].citye].litre=blood[road[i].citys].litre;
else
blood[road[i].citye].litre=blood[road[i].citys].litre+1;
DFS(road[i].citye,dst);
}
return ;
}
int main()
{
int cases,times=0;
scanf(“%d” ,&cases);
while (cases–)
{
int i,j,n,start,cost,t1,t2;
numR=0;
numC=0;
char city1[NUMN],city2[NUMN];
scanf(“%d” ,&n);
for (i=0;i<n;i++)// 对城市进行预处理,把它用数字表示
{
scanf(“%s%s%d%d” ,city1,city2,&start,&cost);
start=(start+6)%24;// 预处理时间,将其旅行时间变为0:00-12:00
if (start+cost<=12)// 如果吸血鬼不能在0:00-12:00 之间完成旅行,则舍去这条路
{
t1=-1;
t2=-1;
for (j=0;j<numC;j++)
{
if (strcmp(city1,city[j])==0)
t1=j;
if (strcmp(city2,city[j])==0)
t2=j;
}
if (t1==-1)// 起点城市未出现过
{
strcpy(city[numC],city1);
t1=numC;
numC++;
}
if (t2==-1)// 终点城市未出现过
{
strcpy(city[numC],city2);
t2=numC;
numC++;
}
road[numR].citys=t1;
road[numR].citye=t2;
road[numR].cost=cost;
road[numR].start=start;
numR++;
}
}
scanf(“%s%s” ,city1,city2);
t1=-1;
t2=-1;
for (i=0;i<numC;i++)
{
if (strcmp(city1,city[i])==0)
t1=i;
if (strcmp(city2,city[i])==0)
t2=i;
}
printf(“Test Case %d./n” ,++times);
if (t1==-1||t2==-1)// 如果起点城市或者终点城市不在路径出现的城市中,则不可能找到路
{
printf(“There is no route Vladimir can take./n” );
continue ;
}
for (i=0;i<numC;i++)
{
blood[i].arrive=0;
blood[i].litre=INF;
}
ans=INF;
blood[t1].litre=0;
DFS(t1,t2);
if (ans!=INF)
printf(“Vladimir needs %d litre(s) of blood./n” ,ans);
else
printf(“There is no route Vladimir can take./n” );
}
return 0;
}