【最短路-负环】Extended Traffic LightOJ

Extended Traffic LightOJ - 1074

题意:

(n)个路口,每一个路口有一个拥挤度(A_i),从一个路口(I)到另一个路口(J)的收益为:((A_J−A_I)^3)。问从第(1)个路口到达第(k)个路口的最小收益。如果不能到达或收益<3,输出“?”,否则输出最小收益。

思路:

注意到路径收益可能是负的,也就是说需要判负环。Dijkstra会死循环,Floyd可能超时,只能SPFA。模板中是遇到迭代次数>n的节点就判定存在负环然后return,这里要稍微改动一下,需要将这个节点及与其相连的其它节点全部设定为不可到达(因为该节点会不断更新其它相连节点,导致那些节点的d值不断减小)。

这题两个教训:一是链式前向星的边数组可能要开到很大……比如这题开到了maxn*1000;二是memset初始化数组为INF时,可能不能正确判断d[i]==INF,还是用for循环初始化吧

int num = 0;
int n, m;
int head[maxn];
bool done[maxn];
LL d[maxn];
LL busy[maxn];
int cnt[maxn];
bool can_reach[maxn];


struct Edge {
    int next, to;
    LL dis;
}edges[maxn*1000];

void add_edge(int from, int to, LL dis) {
    num++;
    edges[num].next = head[from];
    edges[num].to = to;
    edges[num].dis = dis;
    head[from] = num;
}

void dfs(int u) {
    //由于d值为负的节点会不断更新其他与其相连的其它节点
    //所以与其相连或间接相连的点要全部改为不可到达
    for (int i = head[u]; i != 0; i = edges[i].next) {
        int v = edges[i].to;
        if (!can_reach[v]) continue;
        can_reach[v] = false;
        dfs(v);
    }
}

void spfa(int s) {
    queue<int> q;
    d[s] = 0;
    done[s] = true;
    q.push(s);
    cnt[s]++;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        done[u] = false;
        if (!can_reach[u]) continue;
        for (int i = head[u]; i != 0; i = edges[i].next) {
            Edge& e = edges[i];
            if (d[u] < INF && d[u] + e.dis < d[e.to]) {
                d[e.to] = d[u] + e.dis;
                if (cnt[e.to] > n) {
                    dfs(e.to);
                    can_reach[e.to] = false;
                    continue;
                }
                if (!done[e.to]) {
                    q.push(e.to);
                    done[e.to] = true;
                    ++cnt[e.to];
                }
            }
        }
    }
}

void init() {
    num = 0;
    memset(head, 0, sizeof(head));
    for (int i = 0; i <= n; i++) d[i] = INF;
    memset(done, false, sizeof(done));
    memset(edges, 0, sizeof(edges));
    memset(busy, 0, sizeof(busy));
    memset(cnt, 0, sizeof(cnt));
    memset(can_reach, true, sizeof(can_reach));
}

int main()
{
    ios::sync_with_stdio(false);
    FILE* stream1;
  //  freopen_s(&stream1, "output.txt", "w", stdout);
    int t; cin >> t; for(int kase=1;kase<=t;kase++) {
        cin >> n;
        init();
        cout << "Case " << kase <<":" << endl;
        for (int i = 1; i <= n; i++) cin >> busy[i];
        cin >> m;
        for (int i = 1; i <= m; i++) {
            int u, v;
            LL dis;
            cin >> u >> v;
            dis = busy[v] - busy[u];
            dis = dis * dis * dis;
            add_edge(u, v, dis);
        }
        spfa(1);
        int ask;
        cin >> ask;
        while (ask--) {
            int end;
            cin >> end;
            if (!can_reach[end] || d[end] < 3 || d[end] == INF) cout << "?" << endl;
            else cout << d[end] << endl;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/streamazure/p/13419631.html