Codeforces Gym 100338C Important Roads 最短路+Tarjan找桥
原题链接:http://codeforces.com/gym/100338/attachments/download/2136/20062007-winter-petrozavodsk-camp-andrew-stankevich-contest-22-asc-22-en.pdf
题意
给你一个无向图,要从1走到n,问你哪些边去掉之后就没法走原本的最短路了。
题解
跑两发最短路,顺着跑一发,倒着跑一发,对于边(u,v),如果w(u,v)+d[u]+rd[v]或者w(u,v)+d[v]+rd[u]等于最短路,那么边(u,v)就是某条最短路上的边,将这些边标记好后,跑一发Tarjan找桥,这些桥就是答案。需要注意的是有重边。
代码
#include<iostream> #include<queue> #include<cstring> #include<algorithm> #include<vector> #include<cstdio> #include<set> #define INF 21234567890 #define MAX_N 20004 #define MAX_M 112345 using namespace std; typedef long long ll; struct node { public: int u; ll c; node(int uu, ll cc) : u(uu), c(cc) { } node() { } bool operator<(const node &a)const { return c > a.c; } }; struct edge { public: int to; ll cost; bool isShort; int id; edge(int t, ll c,int i) : to(t), cost(c), isShort(0), id(i){ } edge() { } }; priority_queue<node> que; int n, m; struct fuck { public: int u, v, c, id; fuck(int uu, int vv, int cc, int i) : u(uu), v(vv), c(cc), id(i) { } fuck() { } bool operator<(const fuck &a)const{ if(a.u==u){ if(a.v==v)return a.c<c; else return a.v<v; } return a.u<u; } }; set<fuck> se; vector<edge> G[MAX_N]; void dijkstra(int s,ll d[]) { while (que.size())que.pop(); fill(d, d + n + 1, INF); que.push(node(s, 0)); d[s] = 0; while (que.size()) { node now = que.top(); que.pop(); int u = now.u; ll c = now.c; if (d[u] < c)continue; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].to; if (d[v] > d[u] + G[u][i].cost) { d[v] = d[u] + G[u][i].cost; que.push(node(v, d[v])); } } } } ll d[MAX_N],rd[MAX_N]; int father[MAX_N]; int dfn[MAX_N],low[MAX_N],ind=0; bool vis[MAX_N]; int sum=0; bool isBridge[MAX_M]; bool hasSame[MAX_M]; void Tarjan(int u,int p) { father[u] = p; dfn[u] = low[u] = ++ind; vis[u] = 1; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].to; if (v == p||(!G[u][i].isShort))continue; if (!vis[v]) { Tarjan(v,u); low[u] = min(low[u], low[v]); if (low[v] > dfn[u]) { sum++; isBridge[G[u][i].id] = 1; } } else low[u] = min(dfn[v], low[u]); } } bool ans[MAX_M]; int main() { freopen("important.in", "r", stdin); freopen("important.out", "w", stdout); scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int u, v; int c; scanf("%d%d%d", &u, &v, &c); fuck f(u,v,c,i); fuck f0(v,u,c,i); auto it=se.find(f); if(it!=se.end()){ hasSame[it->id]=1; continue; } it=se.find(f0); if(it!=se.end()){ hasSame[it->id]=1; continue; } se.insert(f); G[u].push_back(edge(v, c, i)); G[v].push_back(edge(u, c, i)); } dijkstra(1, d); dijkstra(n, rd); ll sd = d[n]; for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int u = i, v = G[i][j].to; if (d[u] + rd[v] + G[i][j].cost == sd || d[v] + rd[u] + G[i][j].cost == sd) G[i][j].isShort = 1; } Tarjan(1,0); int tot = 0; for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) if (isBridge[G[i][j].id]) ans[G[i][j].id + 1] = 1; for (int i = 1; i <= m; i++)if ((!hasSame[i-1])&&ans[i])tot++; printf("%d\n", tot); for (int i = 1; i <= m; i++) if (ans[i]&&(!hasSame[i-1])) printf("%d ", i); printf("\n"); return 0; }