uva12661

题目描述:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47070

/*
solution:   本题就是最短路径问题,但是在边的权值上做了文章,并不单单只是考虑权值
                而且还要考虑到达一条边的“阀门”时,是否要在门前进行等待,此时权值要加上
                等待的时间。关于dijkstra详见模板开头注释

note:   1.注意需要对是否应该在路口等待做判断,即对权值做判断。
            2.注意对是否能够走一条路的条件“You must enter a road when it’s open, and leave it before it’s closed again.”
            3.对权值的判断此题有如下集中情况。一是不能通过这条路,即走完前面一条路所花时间
            太长,还没到路口。不符合题目中条件,所以此路不能走;二是能够走这条路,但是需要在走下一段路时在路口等待。
            三是不需要等待就可以直接进入下一路
            4.时间状况的判断,详见代码旁边注释

date:   2016/4/21
*/
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>

using namespace std;
const int maxn = 300 + 5;
const int maxm = 50000 + 5;
const int INF = 99999999;
int n, m, s, t, dist[maxn], vis[maxn];

struct Edge {   //定义结构体用来存储边
    int from, to, open, close, time;
};
vector<int> G[maxn];
vector<Edge> edges;

struct HeapNode {   //定义该结构体是为了作为优先队列中的元素类型
    int dist, u;
    bool operator < (const HeapNode& rhs) const {
        return dist > rhs.dist; //仍然定义最小堆的比较器
    }
};

int dijkstra() {
    priority_queue<HeapNode> q;
    for(int i = 0; i <= n; i++)  dist[i] = INF;
    dist[s] = 0;
    memset(vis, 0, sizeof(vis));
    q.push((HeapNode) {0, s});  //将{0, s}  “ 打包 ” 成一个HeapNode类型压入队列,其中的dist成员和u成员值分别为0,s

    while(!q.empty()) {
        HeapNode x = q.top();   q.pop();
        int u = x.u;
        if(vis[u])  continue;
        vis[u] = 1;

        for(int i = 0; i < G[u].size(); i++) {
            Edge& e = edges[G[u][i]];
            int time = e.time;
            int open = e.open;
            int close = e.close;
            int from = e.from;  int to = e.to;
            if(time > open) continue;   //行走这条路所花费的时间大于关闭路径的时间,所以此路不通。这是题目中告知的一条边是否能走的条件

            if(dist[from] % (open + close) + time <= open) {    //不用等待直接进入该路径
                if(dist[to] > dist[from] + time) {  //直接对该边进行松弛操作
                    dist[to] = dist[from] + time;
                    q.push((HeapNode) {dist[to], to});
                }
            } else {    //需要在“阀门前”等待一会
                int wt = dist[from] + time + open + close - dist[from] % (open + close);
                if(dist[to] > wt) {     //“open + close - dist[from] % (open + close)”是等待的时间,所以wt是通过需要的总时间
                    dist[to] = wt;
                    q.push((HeapNode) {dist[to], to});
                }
            }
        }
    }
    return dist[t];
}


int main()
{
    int kase = 0;
    while(scanf("%d%d%d%d", &n, &m, &s, &t) == 4) {
        for(int i = 0; i <= n; i++) G[i].clear();
        edges.clear();  //先对要使用的vector容器进行初始化

        Edge tmp;   //开始读入数据
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d%d%d", &tmp.from, &tmp.to, &tmp.open, &tmp.close, &tmp.time);
            edges.push_back(tmp);   int m = edges.size();
            G[tmp.from].push_back(m - 1);   //注意记录的是边在edges容器中的下标,这样是为了能够访问到权值
        }
        int ans = dijkstra();   //调用dijkstra返回答案
        printf("Case %d: %d\n", ++kase, ans);   //注意格式
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值