最大フロー(Dinic)のC#実装とTopCoder SRM 442 Div1 Hard
タイトルの通り。
まずは最大フロー(Dinic)の実装。
public static partial class Algorithm { public class Edge : IComparable<Edge> { public int from, to; public int length; // 今回これは使わない public int CompareTo(Edge rhs) { if (length == rhs.length) return 0; return length - rhs.length > 0 ? 1 : -1; } public Edge(int f, int t, int l) { from = f; to = t; length = l; } } public static int MaximumFlow(List<List<Edge>> g, int s, int t) { int N = g.Count; int[,] flow = new int[N, N]; int[,] cap = new int[N, N]; int total = 0; for (int u = 0; u < N; ++u) { foreach (Edge e in g[u]) { cap[e.from, e.to] += e.length; } } while (true) { int[] lv = new int[N]; Queue<int> Q = new Queue<int>(); for (int i = 0; i < N; ++i) { lv[i] = -1; } lv[s] = 0; Q.Enqueue(s); for (int d = N; Q.Count > 0 && lv[Q.Peek()] < d; ) { int u = Q.Dequeue(); if (u == t) { d = lv[u]; } foreach (Edge e in g[u]) { if (cap[u, e.to] - flow[u, e.to] > 0 && lv[e.to] == -1) { Q.Enqueue(e.to); lv[e.to] = lv[u] + 1; } } } bool[] finished = new bool[N]; bool ok = false; for (int f = 1; f > 0; ) { f = AugmentingPath(g, cap, flow, lv, finished, s, t, 2000000000); if (f == 0) { break; } total += f; ok = true; } if (!ok) { break; } } return total; } private static int AugmentingPath(List<List<Edge>> g, int[,] cap, int[,] flow, int[] lv, bool[] finished, int u, int t, int cur) { if (u == t || cur == 0) { return cur; } if (finished[u]) { return 0; } finished[u] = true; foreach (Edge e in g[u]) { if (lv[e.to] > lv[u]) { int f = AugmentingPath(g, cap, flow, lv, finished, e.to, t, Math.Min(cur, cap[u, e.to] - flow[u, e.to])); if (f > 0) { flow[u, e.to] += f; flow[e.to, u] -= f; finished[u] = false; return f; } } } return 0; } }
これを使ってSRM 442 Div1のHardが解ける。
public class NowhereLand { public int placeGuards(string[] cities, int k, string[] guards, string[] agencies) { int n = cities.Length; bool[,] E = new bool[n, n]; bool[,] P = new bool[n, k]; bool[,] C = new bool[n, k]; for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) E[i, j] = cities[i][j] == '1'; for (int i = 0; i < n; ++i) { if (guards[i].Length > 0) foreach (int j in Array.ConvertAll<string, int>(guards[i].Split(), int.Parse)) P[i, j] = true; if (agencies[i].Length > 0) foreach (int j in Array.ConvertAll<string, int>(agencies[i].Split(), int.Parse)) C[i, j] = true; } int res = 0; for (int w = 0; w < k; ++w) { List<List<Edge>> g = new List<List<Edge>>(); for (int i = 0; i < 2 + n; ++i) { g.Add(new List<Edge>()); } for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (E[i, j]) { g[i].Add(new Edge(i, j, 1)); } } if (P[i, w]) g[n].Add(new Edge(n, i, 10000)); if (!C[i, w]) g[i].Add(new Edge(i, n + 1, 10000)); } res += MaximumFlow(g, n, n + 1); } return res; } }