【最短路-负环】Extended Traffic LightOJ - 1074
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;
}