次短路
目前只會用dijstra求解。。(貌似有用spfa的。。
當然如果是DAG, 拓撲排序加DP也是可以的。。
次短路的求解和計數
hdu 3191
這道題有邊權爲0的情況。
dij所使用的貪心性質:S是目標集合(已經求得最短路或次短路的點),從 V - S 中選估計值最小的一個u,那麼
如果邊權有0存在, 那麼這條性質就無法保證了。。
幸而數據比較特殊, 只要保證編號小的點先更新就行了。。
// 這道題的數據裏面有權值爲0的情況,pq並不能保證正確
// 詳見 http://acm.hdu.edu.cn/discuss/problem/list.php?problemid=3191
int n, m, src, dst;
struct Edge {
int v, w;
};
vector<Edge> graph[N];
struct Node {
int flag, d, i;
bool operator < (const Node &rhs) const {
if ( d != rhs.d ) return d > rhs.d;
return i > rhs.i;
}
};
const int INF = 1e9;
int d[2][N], cnt[2][N];
bool done[2][N];
void dij() {
memset(done, 0, sizeof(done));
memset(cnt, 0, sizeof(cnt));
fill(d[0], d[0] + n, INF);
fill(d[1], d[1] + n, INF);
d[0][src] = 0;
cnt[0][src] = 1;
d[1][src] = -1;
priority_queue<Node> q;
q.push( (Node) {0, 0, src} );
while(!q.empty()) {
Node fr = q.top(); q.pop();
int u = fr.i, du = fr.d;
if ( done[fr.flag][u] ) continue;
done[fr.flag][u] = 1;
for (int i = 0; i < graph[u].size(); ++i) {
int v = graph[u][i].v, w = du + graph[u][i].w, num = cnt[fr.flag][u];
if ( d[0][v] > w ) {
if ( d[0][v] != INF ) {
d[1][v] = d[0][v];
cnt[1][v] = cnt[0][v];
q.push( (Node) {1, d[1][v], v} );
}
d[0][v] = w;
cnt[0][v] = num;
q.push( (Node) {0, d[0][v], v} );
} else if ( !done[0][v] && d[0][v] == w ) {
cnt[0][v] += num;
} else if ( d[1][v] > w ) {
cnt[1][v] = num;
d[1][v] = w;
q.push( (Node) {1, d[1][v], v} );
} else if ( !done[1][v] && d[1][v] == w ) {
cnt[1][v] += num;
}
}
}
printf("%d %d\n", d[1][dst], cnt[1][dst]);
}
int main() {
#ifdef _LOCA_ENV_
freopen("input.in", "r", stdin);
#endif // _LOCA_ENV
while ( scanf("%d%d%d%d", &n, &m, &src, &dst) != EOF ) {
rep(i, 0, n-1) graph[i].clear();
rep(i, 1, m) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
graph[x].push_back( (Edge) {y, w} );
}
dij();
}
return 0;
}
次短路拓展
lightoj 1099
求無向圖上次短路值, 可以往回走。。
因爲是無向圖, 所以往回走並不影響什麼。。
只要“往回走”得到的次短路比較優, 貪心性質一定會保證它被選中。
也可以不用done數組, 直接用值比較來判斷這個點是否已經用來更新過了。。
int n, m, src, dst;
struct Edge {
int v, w;
};
vector<Edge> graph[N];
struct Node {
int flag, d, i;
bool operator < (const Node &rhs) const {
if ( d != rhs.d ) return d > rhs.d;
return i > rhs.i;
}
};
const int INF = 1e9;
int d[2][N];
bool done[2][N];
void dij() {
memset(done, 0, sizeof(done));
fill(d[0], d[0] + n, INF);
fill(d[1], d[1] + n, INF);
d[0][src] = 0;
d[1][src] = INF;
priority_queue<Node> q;
q.push( (Node) {0, 0, src} );
while(!q.empty()) {
Node fr = q.top(); q.pop();
int u = fr.i, du = fr.d;
if ( done[fr.flag][u] ) continue;
done[fr.flag][u] = 1;
for (int i = 0; i < graph[u].size(); ++i) {
int v = graph[u][i].v, w = du + graph[u][i].w;
if ( d[0][v] > w ) {
if ( d[0][v] != INF ) {
d[1][v] = d[0][v];
q.push( (Node) {1, d[1][v], v} );
}
d[0][v] = w;
q.push( (Node) {0, d[0][v], v} );
} else if ( d[0][v] == w ) {
// pass
} else if ( d[1][v] > w ) {
d[1][v] = w;
q.push( (Node) {1, d[1][v], v} );
}
}
}
}
Dijstra拓展
當最短路徑有多條的時候, 我們可以倒過來遞推出, 所有最短路徑。
還可以對pq使用的HeapNode節點添加一些性質, 在不影響最短路值的情況下, 決定優先用哪些邊來更新。
codeforces 449B - Jzzhu and Cities
在不影響1到各點最短路值的情況下, 儘量去掉 給定邊集裏面的邊。