/* * Network Flow * * Author: Howard Cheng * * The routine network_flow() finds the maximum flow that can be * pushed from the source (s) to the sink (t) in a flow network * (i.e. directed graph with capacities on the edges). The maximum * flow is returned. Note that the graph is modified. If you wish to * recover the flow on an edge, it is in the "flow" field, as long as * is_real is set to true. * * Note: if you have an undirected network. simply call add_edge twice * with an edge in both directions (same capacity). Note that 4 edges * will be added (2 real edges and 2 residual edges). To discover the * actual flow between two vertices u and v, add up the flow of all * real edges from u to v and subtract all the flow of real edges from * v to u. (In fact, for a residual edge the flow is always 0 in this * implementation.) * * This code can also be used for bipartite matching by setting up an * appropriate flow network. * * The code here assumes an adjacency list representation since most * problems requiring network flow have sparse graphs. * * This is the basic augmenting path algorithm and it is not the most * efficient. But it should be good enough for most programming contest * problems. The complexity is O(f m) where f is the size of the flow * and m is the number of edges. This is good if you know that f * is small, but can be exponential if f is large. * */ #include #include #include #include #include using namespace std; struct Edge; typedef list::iterator EdgeIter; struct Edge { int to; int cap; int flow; bool is_real; EdgeIter partner; Edge(int t, int c, bool real = true) : to(t), cap(c), flow(0), is_real(real) {}; int residual() const { return cap - flow; } }; struct Graph { list *nbr; int num_nodes; Graph(int n) : num_nodes(n) { nbr = new list[num_nodes]; } ~Graph() { delete[] nbr; } // note: this routine adds an edge to the graph with the specified capacity, // as well as a residual edge. There is no check on duplicate edge, so it // is possible to add multiple edges (and residual edges) between two // vertices void add_edge(int u, int v, int cap) { nbr[u].push_front(Edge(v, cap)); nbr[v].push_front(Edge(u, 0, false)); nbr[v].begin()->partner = nbr[u].begin(); nbr[u].begin()->partner = nbr[v].begin(); } }; void push_path(Graph &G, int s, int t, const vector &path, int flow) { for (int i = 0; s != t; i++) { if (path[i]->is_real) { path[i]->flow += flow; path[i]->partner->cap += flow; } else { path[i]->cap -= flow; path[i]->partner->flow -= flow; } s = path[i]->to; } } // the path is stored in a peculiar way for efficiency: path[i] is the // i-th edge taken in the path. int augmenting_path(const Graph &G, int s, int t, vector &path, vector &visited, int step = 0) { if (s == t) { return -1; } for (EdgeIter it = G.nbr[s].begin(); it != G.nbr[s].end(); ++it) { int v = it->to; if (it->residual() > 0 && !visited[v]) { path[step] = it; visited[v] = true; int flow = augmenting_path(G, v, t, path, visited, step+1); if (flow == -1) { return it->residual(); } else if (flow > 0) { return min(flow, it->residual()); } } } return 0; } // note that the graph is modified int network_flow(Graph &G, int s, int t) { vector visited(G.num_nodes); vector path(G.num_nodes); int flow = 0, f; do { fill(visited.begin(), visited.end(), false); if ((f = augmenting_path(G, s, t, path, visited)) > 0) { push_path(G, s, t, path, f); flow += f; } } while (f > 0); return flow; } #include int IN(int k) { return 2*k+2; } int OUT(int k) { return IN(k)+1; } const int SRC = 0, SINK = 1; void DFS(const Graph &G, int v, vector &reachable) { reachable[v] = true; for (auto it = G.nbr[v].begin(); it != G.nbr[v].end(); ++it) { auto e = *it; if (e.residual() > 0 && !reachable[e.to]) { DFS(G, e.to, reachable); } } } int main() { int N, R; cin >> N >> R; Graph G(2*N+2); string orig, pref; cin >> orig >> pref; for (int i = 0; i < N; i++) { G.add_edge(IN(i), OUT(i), 1); if (pref[i] != '?') { if (orig[i] == pref[i]) { G.add_edge(SRC, IN(i), 2); } else { G.add_edge(OUT(i), SINK, 2); } } } while (R--) { int i, j; cin >> i >> j; i--; j--; G.add_edge(OUT(i), IN(j), 2); G.add_edge(OUT(j), IN(i), 2); } network_flow(G, SRC, SINK); vector reachable(2*N+2, false); DFS(G, SRC, reachable); for (int i = 0; i < N; i++) { if (reachable[OUT(i)]) { cout << orig[i]; } else if (reachable[IN(i)]) { cout << 'X'; } else { cout << (char)(1-(orig[i]-'A') + 'A'); } } cout << endl; return 0; }