/*
(c) Nathaniel Lim
CS 256, HW 3, #4
Williams College, 3/3/09
Basic Algorithm to find the locations where there should be cameras:
- Maintain a master copy of the original graph
- Iterate through all the nodes in the graph
- delete the given node from the graph, and all edges
- Perform BFS (starting at any element)
- If the size of the BFS tree is < (n-1) the graph is no longer connected
meaning that it was a place that needed to be passed through in a path
between some pair of nodes
- Add the node that was deleted to the return set
*/
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;
import java.io.File;
import java.lang.Integer;
import java.util.ArrayList;
import java.util.Collections;
class Graph {
HashMap<Node, HashSet<Node>> adjList = new HashMap<Node, HashSet<Node>>();
public Graph(){
}
public void addEdge(Node x, Node y){
if (!adjList.containsKey(x) || !adjList.containsKey(y)){
return;
}
HashSet<Node> s = adjList.get(x);
HashSet<Node> r = adjList.get(y);
s.add(y);
r.add(x);
}
public void addNode(Node x){
adjList.put (x, new HashSet<Node>());
}
public HashSet<Node> getAdj(Node x){
return adjList.get(x);
}
public Set<Node> getNodes(){
return adjList.keySet();
}
@SuppressWarnings("unchecked")
public Graph clone(){
Graph output = new Graph();
Set<Node> s = this.getNodes();
for (Node i: s){
output.adjList.put(i, (HashSet<Node>)this.getAdj(i).clone());
}
return output;
}
public Node removeNode(Node x){
if (adjList.containsKey(x)){
HashSet<Node> adjNodes = adjList.get(x);
// Removing all edges referencing x
for (Node n: adjNodes){
HashSet<Node> s = adjList.get(n);
s.remove(x);
}
//Remove the node x itself from graph
adjList.remove(x);
return x;
} else {
return null;
}
}
public String toString(){
String output = "";
Set<Node> s = adjList.keySet();
for (Node n: s){
output += n + ": {";
Set<Node> a = adjList.get(n);
for (Node b: a){
output+=b.label +", ";
}
output+="}\n";
}
return output;
}
}
class Node {
String label;
public String toString(){
return label;
}
public Node(String label){
this.label = label;
}
public boolean equals(Object o){
if (o instanceof Node){
Node a = (Node)o;
return this.label.equals(a.label);
} else {
return false;
}
}
public int hashCode(){
return this.label.hashCode();
}
}
class Main {
public static void printSet(Set x){
String output = "{";
for (Object d: x){
output+=", " + d;
}
output+="}";
System.out.println(output);
}
public static void main (String [] args) throws java.io.FileNotFoundException {
Scanner s = new Scanner(System.in);
int map = 1;
while (true){
int n = Integer.parseInt(s.nextLine());
if (n ==0){
s.close();
return;
}
Graph g = new Graph();
for (int i = 0; i < n; i++){
Node temp = new Node(s.nextLine());
g.addNode(temp);
}
int e = Integer.parseInt(s.nextLine());
for (int i = 0; i < e; i++){
String [] result = s.nextLine().split(" ");
g.addEdge(new Node(result[0]), new Node(result[1]));
}
Set<Node> cameras = new HashSet<Node>();
// Graph Set up, now iterate through nodes, deleting each;
Graph tempGraph;
Set<Node> nodes = g.getNodes();
int graphSize = nodes.size();
for (Node i: nodes){
tempGraph = g.clone();
tempGraph.removeNode(i);
Set<Node> remaining = tempGraph.getNodes();
Set<Node> discovered = new HashSet<Node>();
Set<Node> tempDiscovered = new HashSet<Node>();
//Choose any element in remaining set of nodes
//PERFORM BFS, adding nodes to discovered
// when done, if discovered.size() < size - 1
// then the graph: (g - i) disjoint
Object[] remArray = remaining.toArray();
Node start = (Node)remArray[0];
tempDiscovered.add(start);
discovered.add(start);
//BFS
while (tempDiscovered.size() > 0){
discovered.addAll(tempDiscovered);
tempDiscovered = new HashSet<Node>();
for (Node q: discovered){
HashSet<Node> tempAdj = tempGraph.getAdj(q);
for (Node a: tempAdj){
if (!discovered.contains(a)){
//If an adjacent node hasn't been discovered
//add it to discovered
tempDiscovered.add(a);
}
}
}
}
// If tempGraph was connected, it should be of size: graphSize -1;
if (discovered.size() < graphSize - 1){
cameras.add(i); //The Node originally removed
}
}
System.out.println("City map #" + map + ": " + cameras.size() + " camera(s) found");
ArrayList<String> toSort = new ArrayList<String>();
//Put into alphabetical order
for (Node c: cameras){
toSort.add(c.label);
}
Collections.sort(toSort);
for (String p: toSort){
System.out.println(p);
}
System.out.println("");
map++;;
}
}
}