POJ-2679(最短路+负环判断)

题目中节点数目很多(V<=1100),而边却较少(E <= 5000),因此SPFA的ElogE会明显优于Dijsktra的N^2

需要注意的是SPFA是处理入边邻接矩阵的,所以需要在SPFA处理之前根据输入的出边得到合法的入边

细节点:

(1)为处理单节点负环,队列节点出队后,应立即将对应节点的inq标志置为false

(2)题目要求输出时,先判断有无路径,再判断有无负环,所以在发现负环时,应先看dis[S][D]是否仍为无穷


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define MAX_VERTEX  1100
#define MAX_FEE     200
#define MAX_LENGTH  99999999
#define MAX_COST    99999999

/*********************** datas ***********************/
int N, M, S, D;
struct Edge{
    int to;
    int length;
    int cost;
    Edge(int t, int l, int c):to(t), length(l), cost(c){}
};
vector<Edge> out[MAX_VERTEX], in[MAX_VERTEX];
int  path[MAX_VERTEX][2];
int  times[MAX_VERTEX];
bool inq[MAX_VERTEX];

/********************** procedures ********************/
bool input()
{
    if(scanf("%d%d", &N, &M) != 2) return false;
    for(int i = 0; i < N; ++i){
        out[i].clear();
        in[i].clear();
    }
    
    scanf("%d%d", &S, &D);
    int u, v, fuv, l, fvu;
    for(int i = 0; i < M; ++i){
        while(getchar() != '(') ;
        scanf("%d,%d,%d[%d]%d)", &u, &v, &fuv, &l, &fvu);
        out[u].push_back(Edge(v, l, fuv));
        out[v].push_back(Edge(u, l, fvu));
    }
    return true;
}
void initInRoads()
{
    for(int i = 0; i < N; ++i){
    //find all rewarding roads leaving i
        vector<Edge>& v = out[i];
        int k = v.size();
        if(k > 1){
        //find minimal fee
            int fee = MAX_FEE, j, n = k;
            for(j = 0; j < n; ++j){
                if(v[j].cost < fee) fee = v[j].cost;
            }
            //erase all roads except those have minimal fee
            k = 0;
            for(j = 0; j < n; ++j){
                if(v[j].cost == fee) v[k++] = v[j];
            }
        }
        //set corresponding in roads
        for(int j = 0; j < k; ++j){
            in[v[j].to].push_back(Edge(i, v[j].length, v[j].cost));
        }
    }
}
void spfa()
{
//initialize
    memset(times, 0, N << 2);
    memset(inq, false, N);
    for(int i = 0; i < N; ++i){
        path[i][0] = MAX_LENGTH;
        path[i][1] = MAX_COST;
    }
    path[D][0] = path[D][1] = 0;
//main process
    queue<int> q;
    q.push(D);
    inq[D] = true;
    while(!q.empty()){
        int u = q.front(); q.pop(); inq[u] = false;
        if(++times[u] > N){//negative cycle
            if(path[S][0] < MAX_LENGTH) puts("UNBOUND");
            else puts("VOID");
            return;
        }
        const vector<Edge>& vec = in[u];
        for(int i = 0, n = vec.size(); i < n; ++i){
            int v = vec[i].to;
            if(path[v][1] > path[u][1] + vec[i].cost ||
               path[v][1] == path[u][1] + vec[i].cost &&
               path[v][0] > path[u][0] + vec[i].length){
                path[v][1] = path[u][1] + vec[i].cost;
                path[v][0] = path[u][0] + vec[i].length;
                if(!inq[v]){
                    q.push(v);
                    inq[v] = true;
                }
            }
        }
    }
    if(path[S][0] < MAX_LENGTH) printf("%d %d\n", path[S][1], path[S][0]);
    else puts("VOID");
}

int main()
{
    while(input()){
        initInRoads();
        spfa();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值