/* 题意:一无向图,问至少要割掉几条边破坏最短路,问最多能割掉几条边还能保持最短路 SPFA+Dinic:SPFA求最短路时,用cnt[i]记录到i最少要几条边,第二个答案是m - cnt[n] 最大流==最小割,套个Dinic模板,以后再理解算法。。。 */ #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 2e3 + 10; const int MAXM = 6e4 + 10; const int INF = 0x3f3f3f3f; struct Edge { int v, w; }; struct Flow { int v, cap, rev; }; bool vis[MAXN]; int cnt[MAXN]; int d[MAXN]; int lv[MAXN]; int it[MAXN]; vector<Edge> G[MAXN]; vector<Flow> F[MAXN]; int n, m; void add_edge(int u, int v, int cap) { F[u].push_back ((Flow) {v, cap, (int) F[v].size ()}); F[v].push_back ((Flow) {u, 0, (int) F[u].size ()-1}); } void BFS(int s) { memset (lv, -1, sizeof (lv)); queue<int> Q; Q.push (s); lv[s] = 0; while (!Q.empty ()) { int u = Q.front (); Q.pop (); for (int i=0; i<F[u].size (); ++i) { Flow &e = F[u][i]; if (e.cap > 0 && lv[e.v] < 0) { lv[e.v] = lv[u] + 1; Q.push (e.v); } } } } int DFS(int u, int t, int f) { if(u == t) return f; vis[u] = true; for (int &i=it[u]; i<F[u].size (); ++i) { Flow &e = F[u][i]; if (e.cap > 0 && lv[u] < lv[e.v]) { int d = DFS (e.v, t, min (f, e.cap)); if (d > 0) { e.cap -= d; F[e.v][e.rev].cap += d; return d; } } } return 0; } int Dinic(int s, int t) { int flow = 0, f; for (; ;) { BFS (s); if (lv[t] < 0) return flow; memset (it, 0, sizeof (it)); while ((f = DFS (s, t, INF)) > 0) flow += f; } } void build_graph(void) { for (int i=1; i<=n; ++i) { for (int j=0; j<G[i].size (); ++j) { Edge &e = G[i][j]; if (d[i] + e.w == d[e.v]) { add_edge (i, e.v, 1); add_edge (e.v, i, 0); } } } } void SPFA(int s) { for (int i=1; i<=n; ++i) { d[i] = (i == s) ? 0 : INF; cnt[i] = (i == s) ? 0 : INF; } memset (vis, false, sizeof (vis)); vis[s] = true; queue<int> Q; Q.push (s); while (!Q.empty ()) { int u = Q.front (); Q.pop (); vis[u] = false; for (int i=0; i<G[u].size (); ++i) { int v = G[u][i].v, w = G[u][i].w; if (d[v] == d[u] + w) cnt[v] = min (cnt[v], cnt[u] + 1); if (d[v] > d[u] + w) { d[v] = d[u] + w; cnt[v] = cnt[u] + 1; if (!vis[v]) { vis[v] = true; Q.push (v); } } } } } int main(void) { //HDOJ 5294 Tricks Device //freopen ("G.in", "r", stdin); while (scanf ("%d%d", &n, &m) == 2) { for (int i=1; i<=n; ++i) G[i].clear (); for (int i=1; i<=n; ++i) F[i].clear (); for (int i=1; i<=m; ++i) { int u, v, w; scanf ("%d%d%d", &u, &v, &w); G[u].push_back ((Edge) {v, w}); G[v].push_back ((Edge) {u, w}); } SPFA (1); build_graph (); printf ("%d %d ", Dinic (1, n), m - cnt[n]); } return 0; }