Dijkstra算法的步骤:
1:集合初始化:集合Q置空,集合S中存所有节点
2:从集合S中取出最短路径点s(第一步时取起点),从S中移除,加入Q
3:松弛:s加入Q后,更新S集合中的距离
4:循环执行1,2,3直到S集合为空
关键点:
如果需要输出路径,应保存新加入节点的前置节点。对每个加入集合Q的节点,前置节点只有最多一个,后置节点有可能有多个。
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class URAL1072 {
static {
//System.setIn(URAL1072.class.getResourceAsStream("/URAL1072.txt"));
}
private static PrintWriter stdout = new PrintWriter(System.out);
//private static StreamTokenizer stdin = new StreamTokenizer(new InputStreamReader(System.in));
private static Scanner stdin = new Scanner(System.in);
private static int N;
private static int START;
private static int END;
private static Computer[] allComputers = new Computer[90];
private static Boolean[][] D = new Boolean[90][90];//two computer is connected or not
/**
* @param args
*/
public static void main(String[] args) throws IOException {
init();
readData();
//printMatrix();
dijkstra();
printResult();
}
private static void init() {
for (int i = 0; i < 90; i++) {
allComputers[i] = null;
}
for (int i = 0; i < 90; i++) {
for (int j = 0; j < 90; j++) {
D[i][j] = Boolean.FALSE;
}
}
}
private static void readData() throws IOException {
N = stdin.nextInt();
for (int i = 0; i < N; i++) {
int K = stdin.nextInt();
IPAddress[] ips = new IPAddress[K];
for (int j = 0; j < K; j++) {
ips[j] = readIp();
}
Computer c = new Computer(i, ips);
allComputers[i] = c;
}
START = stdin.nextInt() - 1;
END = stdin.nextInt() - 1;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
Computer computers1 = allComputers[i];
Computer computers2 = allComputers[j];
if (computers1.isTransmited(computers2)) {
D[i][j] = Boolean.TRUE;
D[j][i] = Boolean.TRUE;
} else {
D[i][j] = Boolean.FALSE;
D[j][i] = Boolean.FALSE;
}
}
}
}
private static IPAddress readIp() throws IOException {
String line = stdin.nextLine();
while (line.trim().length() == 0) {
line = stdin.nextLine();
}
String[] ips = line.split(" ");
int[] ip = parseIp(ips[0]);
int[] mask = parseIp(ips[1]);
IPAddress a = new IPAddress(ip, mask);
return a;
}
private static int[] parseIp(String s) {
String[] ips = s.split("\\.");
int[] ip = new int[4];
for (int i = 0; i < 4; i++) {
ip[i]= Integer.parseInt(ips[i]);
}
return ip;
}
private static void dijkstra() {
List<Computer> list1 = new ArrayList<Computer>(90);
List<Computer> list2 = new ArrayList<Computer>(90);
//init list2
for (int i = 0; i < N; i++) {
list2.add(allComputers[i]);
}
while(!list2.isEmpty()) {
int min = -1;
Computer newComputer = null;
if (!list1.isEmpty()) {
for (Computer c : list2) {
if (c.distance < min || min == -1) {
newComputer = c;
min = c.distance;
}
}
} else {
newComputer = allComputers[START];
newComputer.distance = 0;
newComputer.pre = null;
}
list2.remove(newComputer);
list1.add(newComputer);
if (newComputer.index == END) { //found,needn't to continue
break;
}
if (newComputer.distance == Integer.MAX_VALUE) {
break;
}
for (Computer c : list2) {
if (D[newComputer.index][c.index]) {
c.distance = newComputer.distance + 1;
c.pre = newComputer;
}
}
}
}
private static void printResult() {
Computer end = allComputers[END];
if (end != null && end.pre != null) {
stdout.println("Yes");
int[] result = new int[end.distance + 1];
Computer c = end;
int index = 0;
while (c != null) {
result[index++] = c.index;
c = c.pre;
}
for (int i = result.length - 1; i >= 0; i --) {
stdout.print(result[i] + 1);
if (i != 0) {
stdout.print(' ');
}
}
} else {
stdout.print("No");
}
stdout.println();
stdout.flush();
}
static class IPAddress {
public int[] ip;
public int[] mask;
public int[] subnet;
public IPAddress(int[] ip, int[] mask) {
this.ip = ip;
this.mask = mask;
this.subnet = IPAddress.getSubNet(ip, mask);
}
static int[] getSubNet(int[] ip, int[] mask) {
int[] s = new int[4];
for (int i = 0; i < 4; i++) {
s[i] = ip[i] & mask[i];
}
return s;
}
public boolean isSubnetSame(IPAddress another) {
for (int i = 0; i < 4; i++) {
if (this.subnet[i] != another.subnet[i]) {
return false;
}
}
return true;
}
}
static class Computer {
public IPAddress[] ips;
public int distance = 0;
public int index;
public Computer pre = null;//can't save next,cause there may be more than one 'next'
public Computer(int index, IPAddress[] ips) {
this.index = index;
this.ips = ips;
this.distance = Integer.MAX_VALUE;
}
//to determin whether this computer can transmit to the given one
public boolean isTransmited(Computer another) {
IPAddress[] ips1 = this.ips;
IPAddress[] ips2 = another.ips;
for (int x = 0; x < ips1.length; x++) {
IPAddress ip1 = ips1[x];
for (int y = 0; y < ips2.length; y++) {
IPAddress ip2 = ips2[y];
if (ip1 != null && ip2 != null && ip1.isSubnetSame(ip2)) {
return true;
}
}
}
return false;
}
}
}