1. 

/**
* FWP, Ausgewählte Probleme aus dem ACM Programming Contest, WS10/11
* Problem: 117 - The Postal Worker Rings Once
* Link: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=53
*
* @author Philippe Brousse
* @version 1.0, 10/23/2010
*
* Method : Ad-Hoc
* Status : Accepted
* Runtime: 0.112
*/
package postalworker;

import java.io.*;
import java.util.*;

/**
*
* @author Philippe Brousse
* @version 1.0
*/
public class Main
{

static Graph graph;

/**
* @param args
*/
public static void main(String... args) throws IOException
{
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
do
{
//TODO: Andere Speichermöglichkeit verwenden
//erste Straþe einlesen
String in = input.readLine().trim();
LinkedList<String> strassen = new LinkedList<String>();
graph = new Graph();

//Alle weiteren Straþen einlesen
do
{
//Strasse in die Strassenliste
strassen.add(in);
//Kreuzungen der Strasse
char von = in.charAt(0);
char nach = in.charAt(in.length() - 1);
//Strasse an Kreuzung 1...
if (!graph.contains(von))
{
//System.out.println("Neuer Knoten: " + von);
graph.add(new Node(von));
}
//Kein Check: jede Strasse hat eine einzigartige Kombination
//aus erstem und letztem Buchstaben!!!
//an den Knoten 'von' den Knoten 'nach' samt Kosten anhängen
//System.out.println("Hänge " + nach + " an " + von + " an");
graph.get(von).add(nach, in.length());

//...und 2 anhängen
if (!graph.contains(nach))
{
//System.out.println("Neuer Knoten: " + nach);

graph.add(new Node(nach));
}
//an den Knoten 'nach' den Knoten 'von' samt Kosten anhängen
//System.out.println("Hänge " + von + " an " + nach + " an");

graph.get(nach).add(von, in.length());

//nächste Strasse
in = input.readLine().trim();
}
//hier: wenn deadend gelesen -> Ende, String wird verworfen
while (!in.equals("deadend"));
//besitzt der Graph einen Eulerkreis?
boolean eulerkreis = true;
//Speicher Knoten mit ungeradem Grad
Node[] odd = new Node[2];
int i = 0;
for (Node n : graph.nodes())
{

if (n.getNeighbours().keySet().size() % 2 == 1)
{
eulerkreis = false;
odd[i] = n;
i++;
}

}


int length = 0;
//Jede Strasse wird genau einmal passiert
for (String s : strassen)
{
length += s.length();
}
if (!eulerkreis)
{
//TODO: kürzesten Weg von einem ungeraden Knoten zum Anderen finden -> Floyd-Warshall
//Summe der Grade aller Knoten positiv!!!! -> nicht 1 ungerader Knoten
Node start = odd[0];
Node end = odd[1];

Node nowAt = start;
start.setPathLength(0);
PriorityQueue<Node> open = new PriorityQueue<Node>();
open.offer(start);
while (!open.isEmpty())
{
nowAt = open.poll();
for (Node n : nowAt.getNeighbours().keySet())
{
int newPath = nowAt.pathLength + nowAt.getNeighbours().get(n);
if (n.pathLength > newPath)
{
n.setPathLength(newPath);
open.offer(n);
}
}

}
//Wegkosten errechnen:
length += graph.get(end).getPathLength();


// graph.get(odd[i]);
}
System.out.println(length);

}
//nichts mehr zu lesen -> Ende Programm
while (input.ready());
}

private static class Node implements Comparable<Node>
{

private final char name;
private final Map<Node, Integer> neighbours;
private int pathLength = Integer.MAX_VALUE;
private Node pred = null;

public Node getPred()
{
return pred;
}

public void setPred(Node pred)
{
this.pred = pred;
}

public int getPathLength()
{
return pathLength;
}

public void setPathLength(int pathLength)
{
this.pathLength = pathLength;
}

void add(char n, int costs)
{

if (graph.get(n) == null)
{
graph.add(new Node(n));
}
neighbours.put(graph.get(n), costs);
graph.get(n).getNeighbours().put(this, costs);
}

Node(char name)
{
this.name = name;
neighbours = new HashMap<Node, Integer>();
}

public char getName()
{
return name;
}

public Map<Node, Integer> getNeighbours()
{
return neighbours;
}

@Override
public int hashCode()
{
return (int) name;
}

@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Node other = (Node) obj;
if (this.name != other.name)
{
return false;
}
return true;
}

@Override
public int compareTo(Node o)
{
return this.pathLength - o.getPathLength();
}

@Override
public String toString()
{
return "Node[" + name + "]";
}
}

private static class Graph
{

private final List<Node> nodes;

Graph()
{
nodes = new LinkedList<Node>();
}

boolean contains(char name)
{
return nodes.contains(new Node(name));
}

List<Node> nodes()
{
return nodes;
}

Node get(char name)
{
for (Node n : nodes)
{
if (n.getName() == name)
{
return n;
}
}
return null;
}

Node get(Node m)
{
return get(m.getName());
}

void add(Node n)
{
nodes.add(n);
}
}
}