分析
一个简单的思路是枚举删除每一条边,然后跑堆优化dijkstra算法。但这样的复杂度恐怕过大。因此有一个简单的优化思路:第一次跑dijkstra时记录路径上的点。显然,堵车的路一定处于这些点之间,因为如果不是,玛丽卡走原先的最短路一定最短。因此只需要枚举删除处于最短路上的点之间的边,再跑堆优化dijkstra即可。代码使用zkw树优化。
示例代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
// basic of graph
struct p {
int to, next, dis;
}edge[3000000];
int head[1005], top = 0;
void push(int i, int j, int k)
{
edge[++top].to = j;
edge[top].dis = k;
edge[top].next = head[i];
head[i] = top;
}
// a heap
class zkw_tree {
int dat[2050];
int from[2050];
int n;
public:
zkw_tree()
{
memset(dat, 127/3, sizeof dat);
for (int i = 1; i < 2050; i++)
from[i] = i-n+1;
}
void clear()
{
memset(dat, 127/3, sizeof dat);
for (int i = 1; i < 2050; i++)
from[i] = i-n+1;
}
void init(int num)
{
n = num;
}
void modify(int i, int new_val)
{
dat[i+n-1] = new_val;
for (int pos = (i+n-1)>>1; pos; pos>>=1) {
int lft = pos<<1, rgt = (pos<<1)+1;
if (dat[lft] <= dat[rgt]) {
dat[pos] = dat[lft];
from[pos] = from[lft];
} else {
dat[pos] = dat[rgt];
from[pos] = from[rgt];
}
}
}
int query()
{
return from[1];
}
int top()
{
return dat[1];
}
}zkw_heap;
// some var & func
int forbid_s = 0, forbid_t = 0;
int n, m;
bool eq(int a, int b, int c, int d)
{
return (a == c && b == d) || (a == d && b == c);
}
// dijkstra
int dis[1005], pre[1005];
int dijkstra(bool take_path = false)
{
memset(dis, 127/3, sizeof dis);
dis[1] = 0;
zkw_heap.clear();
zkw_heap.modify(1, 0);
for (int i = 1; i < n; i++) {
int k = zkw_heap.query();
dis[k] = zkw_heap.top(); zkw_heap.modify(k, 233333333);
//cout << k << " " << dis[k] << endl;
if (k == n) break;
for (int j = head[k]; j; j = edge[j].next) {
int to = edge[j].to, d = edge[j].dis;
if (dis[to] > dis[k]+d && !eq(k, to, forbid_s, forbid_t)) {
dis[to] = dis[k]+d;
if (take_path)
pre[to] = k;
zkw_heap.modify(to, dis[to]);
}
}
}
return dis[n];
}