#include #include #include #include #include #include #include #include #include class Node; struct Edge { Node* to; int dist; Edge(Node* t, int d) : to(t), dist(d) {} }; class Node { public: Node(std::string n = "node") : name(n){}; std::list edgeTo; int reachIter = -1; Node *parent = nullptr; std::string name; }; Node* nodesIn[40][40]; Node* nodesOut[40][40]; int inf = 100000000; void addGridEdge(Node *nIn, Node *nOut) { nOut->edgeTo.push_back(Edge(nIn, inf)); nIn->edgeTo.push_back(Edge(nOut, 0)); } void solve(std::istream &in) { int width, height; in >> width; in >> height; // Create nodes //*nodesIn.resize(height); //*nodesOut.resize(height); for (int iH = 0; iH < height; iH++) { //*nodesIn[iH].resize(width); //*nodesOut[iH].resize(width); for (int iW = 0; iW < width; iW++) { nodesIn[iH][iW] = new Node(); nodesOut[iH][iW] = new Node(); } } Node *source = new Node("source"); Node *target = new Node("target"); // Read in nodes for (int iH = 0; iH < height; iH++) { char g[width + 1]; in >> g; //std::cout << "g = " << g << " iH = " << iH << std::endl; for (int iW = 0; iW < width; iW++) { Node *nIn = nodesIn[iH][iW]; Node *nOut = nodesOut[iH][iW]; // Create incoming adjacency connections if (iH > 0) { addGridEdge(nIn, nodesOut[iH - 1][iW]); } if (iH + 1 < height) { addGridEdge(nIn, nodesOut[iH + 1][iW]); } if (iW > 0) { addGridEdge(nIn, nodesOut[iH][iW - 1]); } if (iW + 1 < width) { addGridEdge(nIn, nodesOut[iH][iW + 1]); } // in to out connection char gVal = g[iW]; if (gVal >= '0' && gVal <= '9') { nIn->edgeTo.push_back(Edge(nOut, gVal - '0')); nOut->edgeTo.push_back(Edge(nIn, 0)); } else { nIn->edgeTo.push_back(Edge(nOut, inf)); nOut->edgeTo.push_back(Edge(nIn, 0)); } // Source/sink connections if (gVal == 'A') { source->edgeTo.push_back(Edge(nIn, inf)); nIn->edgeTo.push_back(Edge(source, 0)); } if (gVal == 'B') { nOut->edgeTo.push_back(Edge(target, inf)); target->edgeTo.push_back(Edge(nOut, 0)); } } } int flowCount = 0; // Flow while (true) { std::deque Q; Q.push_back(source); source->reachIter = flowCount; bool found = false; while (!Q.empty()) { Node *c = Q.front(); Q.pop_front(); //std::cout << " popping node " << c->name //<< " reachIter = " << c->reachIter << std::endl; //if (c->parent != nullptr) { //std::cout << " parent = " << c->parent->name << std::endl; //} // Found path if (c == target) { found = true; break; } // Add neighbors for (auto p : c->edgeTo) { Node *pn = p.to; if (pn == c) throw std::runtime_error("self edge!"); int resid = p.dist; if (resid <= 0) continue; if (pn->reachIter == flowCount) continue; pn->reachIter = flowCount; pn->parent = c; Q.push_back(pn); } } // No path found if (!found) { break; } // Process path // int minCap = inf; // Node* currN = target; // while(currN->parent != nullptr) { // Node* prevN = currN->parent; // minCap = std::min(minCap, prevN->edgeTo[currN]); // currN = prevN; //} Node *currN = target; int minCap = 1; //std::cout << "walking path" << std::endl; while (currN->parent != nullptr) { //std::cout << " currN = " << currN << std::endl; Node *prevN = currN->parent; for (Edge& edge: prevN->edgeTo) { if (edge.to == currN) edge.dist -= minCap; } for (Edge& edge: currN->edgeTo) { if (edge.to == prevN) edge.dist += minCap; } currN = prevN; } flowCount++; } std::cout << flowCount << std::endl; } int main(int argc, char **argv) { if (argc > 1) { std::ifstream in(argv[1]); solve(in); } else { solve(std::cin); } return 0; }