Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Problem H:
Sightseeing Tour

KM city has $N$ sightseeing areas. Currently every pair of area is connected by a bidirectional road.

However for some reason, Mr. KM, the mayor of this city, decided to make all of these roads one-way . It costs $C_{i, j}$ dollars to renovate the road between area $i$ and area $j$ to a one-way road from area $i$ to area $j$. Of course, Mr. KM is economic and wants to minimize the total cost of the renovation.

On the other hand, because tourism is the most important industry for KM city, there must exists a tour that goes through all the sightseeing areas, visiting each area exactly once. The first and last area of the path need not to be the same. Can you calculate the minimum total cost required for the renovation, given this situation?

Input

The first line contains the number of sightseeing area $N$ ($1 \leq N \leq 100$). Next $N$ lines describe the integer matrix $C$, where the $j$-th element of the $i$-th row of the input describes $C_{i,j}$ ($0 \leq C_{i,j} \leq 1,000,000$). For each $i$, you can assume $C_{i,i}$ is always zero.

Output

Output the minimum cost in a line.

Sample Input 1

3
0 2 7
2 0 4
5 8 0

Sample Output 1

11

Solution in JAVA (judge verdict: Accepted)

import java.io.*;
import java.util.*;
import java.lang.ArrayIndexOutOfBoundsException;
import java.math.BigInteger;

/**
 * @author yoshikyoto
 */
class Main extends MyUtil{
	public static void main(String[] args) throws Exception{
		int n = readInt();
		int[][] c = new int[n][];
		for (int i = 0; i < n; i++) {
			c[i] = readIntMap();
		}
		
		long ans = 0;
		for(int i = 0; i < n; i++){
			for(int j = 0; j < i; j++){
				ans += Math.min(c[i][j], c[j][i]);
			}
		}
		System.out.println(ans);
	}
}

// public static Graph g;

/**
 * グラフのノード
 */
class Node extends ArrayList<Edge> {
	int index, depth = -1, dist = -1;

	Node(int index) {
		this.index = index;
	}

	Node parent;
	boolean visited = false;
}

/**
 * グラフのエッジ
 */
class Edge {
	int from, to, cost;

	Edge(int from, int to, int cost) {
		this.from = from;
		this.to = to;
		this.cost = cost;
	}
}

/**
 * ダイクストラのためにノードの大きさを比較できるようにしておく
 */
class NodeComparator implements Comparator<Node> {
	public int compare(Node a, Node b) {
		return a.dist - b.dist;
	}
}

class Graph {
	Node n[];

	/**
	 * ノードの数でグラフを初期化
	 */
	Graph(int node_count) {
		n = new Node[node_count];
		for (int i = 0; i < node_count; i++)
			n[i] = new Node(i);
	}

	/**
	 * エッジのfromをもとにノードをエッジを追加
	 */
	public void add(Edge e) {
		n[e.from].add(e);
	}

	public Node getNode(int i) {
		return n[i];
	}

	public Node lca(int a, int b) {
		// 浅い方をaとする
		Node nodeA, nodeB;
		if (n[a].depth < n[b].depth) {
			nodeA = n[a];
			nodeB = n[b];
		} else {
			nodeA = n[b];
			nodeB = n[a];
		}
		// 同じ深さまで親をたどる
		int diff = nodeB.depth - nodeA.depth;
		for (int k = 0; k < diff; k++) {
			nodeB = nodeB.parent;
		}
		// 共通祖先を見つける
		while (nodeA != nodeB) {
			nodeA = nodeA.parent;
			nodeB = nodeB.parent;
		}
		return nodeA;
	}

	public void calcDepth(int root) {
		ArrayDeque<Integer> que = new ArrayDeque<Integer>();
		que.push(root);
		n[root].depth = 0;

		while (que.size() > 0) {
			int curr = que.pop();
			Node curr_node = n[curr];
			for (Edge e : curr_node) {
				int next = e.to;
				Node next_node = n[next];
				if (next_node.depth == -1) {
					next_node.depth = curr_node.depth + 1;
					next_node.parent = curr_node;
					que.push(next);
				}
			}
		}
	}

	public int[] dijkstra(int s) {
		PriorityQueue<Node> q = new PriorityQueue<Node>(n.length,
				new NodeComparator());
		Node start_node = new Node(s);
		start_node.dist = 0;
		q.add(start_node);
		int[] dist = new int[n.length];
		for (int i = 0; i < dist.length; i++)
			dist[i] = -1;
		dist[s] = 0;

		while (q.size() > 0) {
			Node currNode = q.poll();
			if (dist[currNode.index] < currNode.dist)
				continue;
			for (Edge e : n[currNode.index]) {
				Node nextNode = new Node(e.to);
				nextNode.dist = currNode.dist + e.cost;
				if (dist[e.to] == -1 || dist[e.to] > nextNode.dist) {
					dist[e.to] = nextNode.dist;
					q.add(nextNode);
				}
			}
		}
		return dist;
	}
}

// --- ここから下はライブラリ ----------
/**
 * MyUtil
 * @author yoshikyoto
 */
class MyUtil {
	public static int toInt(boolean[] a){
		int pow = 1, ret = 0, l = a.length;
		for(int i = 0; i < l; i++){
			if(a[i]) ret += pow;
			pow *= 2;
		}
		return ret;
	}
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	public static int ins[];
	public static int[] readIntMap() throws IOException{return parseInt(readLine().split(" "));}
	public static int readIntMap(int i) throws Exception{
		if(i == 0) ins = readIntMap();
		return ins[i];
	}
	public static int[][] readIntMap(int n, int m) throws IOException{
		int[][] ret = new int[n][];
		for(int i = 0; i < n; i++) ret[i] = readIntMap();
		return ret;
	}
	public static int[] readIntToMap(int n) throws IOException{
		int[] ret = new int[n];
		for(int i = 0; i < n; i++) ret[i] = readInt();
		return ret;
	}
	public static int[] readNoDistIntMap() throws IOException{
		String[] strs = readLine().split("");
		int l = strs.length;
		int[] ret = new int[l-1];
		for(int i = 1; i < l; i++)
			ret[i-1] = parseInt(strs[i]);
		return ret;
	}
	public static String readLine() throws IOException{return br.readLine();}
	public static int readInt() throws IOException{return Integer.parseInt(br.readLine());}
	public static int[] parseInt(String[] arr){
		int[] res = new int[arr.length];
		for(int i = 0; i < arr.length; i++)res[i] = Integer.parseInt(arr[i]);
		return res;
	}
	public static double[] parseDouble(String[] arr){
		double[] res = new double[arr.length];
		for(int i = 0; i < arr.length; i++)res[i] = Double.parseDouble(arr[i]);
		return res;
	}
	public static boolean[] parseBool(String[] arr){
		int[] t = parseInt(arr);
		boolean[] res = new boolean[t.length];
		for(int i = 0; i < t.length; i++){
			if(t[i] == 1){res[i] = true;
			}else{res[i] = false;}
		}
		return res;
	}
	public static int parseInt(Object o){
		return Integer.parseInt(o.toString());
	}
}