In this puzzle, Skynet Agent is trying to escape from a graph by travelling from node to node until the closest exit node. The aim is to prevent it from doing so, by removing edges of the graph. As each node can only be connected to one exit node, a solution is to find each turn one of the shortest paths to exit and cut it.
import java.util.*; /** * <b> Node is the class representing a node of the network. </b> Each node as : * <ul> * <li> a unique id, constant * <li> a list of neighbour nodes * </ul> */ class Node { private final int n; private LinkedList<Node> neighb; public Node(int n) { this.n = n; neighb = new LinkedList<Node>(); } public void addNeighb(Node m) { neighb.add(m); } public void removeNeighb(Node m) { neighb.remove(m); } public Node[] neighb() { return neighb.toArray(new Node[neighb.size()]); } public int n() { return n; } } /** * <b> Path is the class representing a path in the network, by a list of nodes </b> */ class Path { private LinkedList<Node> p; public Node getNode(int i) { return p.get(i); } public int length() { return p.size(); } public void addFirst(Node n) { p.addFirst(n); } public Path() { p = new LinkedList<Node>(); } /** This constructor builds a shortest path in the network described by * nodes, between begin and end */ public Path (Node begin, Node end, Node[] nodes) { p = new LinkedList<Node>(); int N = nodes.length; /* For each node is kept a boolean equal to true if it has been visited and an int equal to the node it has been visited from (initially = -1) */ boolean[] explored = new boolean[N]; for (int i=0; i < N ;i++) explored[i] = false; explored[begin.n()] = true; int[] prec = new int[N]; for (int i=0; i < N; i++) prec[i] = -1; /* A BFS is performed, starting from node begin and until finding the node end.*/ LinkedList<Node> q = new LinkedList<Node>(); q.add(begin); Node n = null; while((q.size() != 0) && (n = q.remove()) != end) { for (Node m : n.neighb()) { if(!explored[m.n()]) { explored[m.n()] = true; prec[m.n()] = n.n(); q.add(m); } } } /* if the queue is empty before finding the node end then there is no path, the new path stays empty. Else, a shortest path is identified by backtracing.*/ if (n == end) { while(n != begin) { this.addFirst(n); n = nodes[prec[n.n()]]; } this.addFirst(n); } } } class Player { public static void cut(Node n1, Node n2){ n1.removeNeighb(n2); n2.removeNeighb(n1); System.out.println(n1.n() + " " + n2.n()); } public static void main(String args[]) { Scanner in = new Scanner(System.in); // Scanning number of nodes, links, and exits int N = in.nextInt(); int L = in.nextInt(); int E = in.nextInt(); // Initializing an array of non-linked nodes Node[] nodes = new Node[N]; for (int i = 0 ; i < N ; i++) nodes[i] = new Node(i); // Linking nodes for (int i = 0; i < L; i++) { int N1 = in.nextInt(); int N2 = in.nextInt(); nodes[N1].addNeighb(nodes[N2]); nodes[N2].addNeighb(nodes[N1]); } // Initializing an array of exit nodes Node[] exits = new Node[E]; for (int i = 0; i < E; i++) exits[i] = nodes[in.nextInt()]; while (true) { // Skynet agent position int SI = in.nextInt(); /* Simple strategy : identify one shortest paths from Skynet agent to each exit node, thanks to a Breadth First Searches Then cutting the shortest, as close as possible to Skynet agent */ Path[] shortestPaths = new Path[E]; int minLength = Integer.MAX_VALUE; Path pathToCut = null; for (int i = 0 ; i < E ; i++) { shortestPaths[i] = new Path(nodes[SI], exits[i], nodes); int length = shortestPaths[i].length(); if ((length != 0) && (length < minLength)) { minLength = length; pathToCut = shortestPaths[i]; } } cut(pathToCut.getNode(0), pathToCut.getNode(1)); } } }
This code implements the same algorithm as in Java. It is a good example of OOP in Python.
import sys, math class Node(object): '''Class representing a node of the network, each node as : a unique id, constant a list of neighbour nodes''' def __init__(self, n =0): self.n = n self.neighb = [] def addNeighb(self, m): self.neighb.append(m) def removeNeighb(self, m): self.neighb.remove(m) class Path(object): '''class representing a path in the network, by a list of node''' def __init__(self, begin, end, nodes): '''This constructor builds a shortest path in the network described by nodes, between begin and end''' self.p = [] N = len(nodes) # explored[i] is True <=> node i has been visited # prec[i] = j <=> node i has been visited coming from node j explored, prec = [], [] for i in range(N): explored.append(False) prec.append(-1) explored[begin.n] = True # A BFS is performed starting from node begin, until finding node end q, n = [], None q.append(begin) while len(q) != 0: n = q.pop() if n == end: break else: for m in n.neighb: if not explored[m.n]: explored[m.n] = True prec[m.n] = n q[0:0] = [m] # if the queue is empty before finding end, there is no path # else a shortest path is identified by backtracking if n == end: while n != begin: self.p[0:0] = [n] n = prec[n.n] self.p[0:0] = [n] def length(self): return len(self.p) def addFirst(self, n): self.p[0:0] = [n] def getNode(self, i): return self.p[i] def cut(n1, n2): '''removes the edge between node n1 and n2''' n1.removeNeighb(n2) n2.removeNeighb(n1) print("{} {}".format(n1.n, n2.n)) # number of nodes, links and exits N, L, E = [int(i) for i in input().split()] # initializing the array of nodes and linking them nodes = [] for i in range(N): nodes.append(Node(i)) for i in range(L): N1, N2 = [int(j) for j in input().split()] nodes[N1].addNeighb(nodes[N2]) nodes[N2].addNeighb(nodes[N1]) # initializing the array of exits exits = [] for i in range(E): exits.append(nodes[int(input())]) while 1: # each turn, identifies one of the shortest paths from Skynet Agent # to each exit node (by a Breadth First Search), then cuts the shortest SI = int(input()) shortestPaths = [] minLength = 9999999 pathToCut = None for i in range(E): shortestPaths.append(Path(nodes[SI], exits[i], nodes)) length = shortestPaths[i].length() if (length != 0) and (length < minLength): minLength = length pathToCut = shortestPaths[i] cut(pathToCut.getNode(0), pathToCut.getNode(1))