Coursera普林斯頓大學演算法下Week3:Baseball Elimination 棒球淘汰賽
阿新 • • 發佈:2019-01-11
本任務的重點在於理解題目的意思,理解了意思很好編碼。
import java.util.HashMap; import edu.princeton.cs.algs4.FlowEdge; import edu.princeton.cs.algs4.FlowNetwork; import edu.princeton.cs.algs4.FordFulkerson; import edu.princeton.cs.algs4.In; import edu.princeton.cs.algs4.Queue; public class BaseballElimination { private final int teamNum; // 球隊數量 private final int[][] g; // 最近待比對戰表 private final String[] teamName; // 球隊隊名錶 private int meachesTeamNum; // 在構建FlowNetwork時表示隊伍之間的比賽節點個數 private int V; // 在構建FlowNetwork時表示節點個數 private int flow; // 在構建FlowNetwork時表示flow值 private HashMap<Integer, Integer> v2id; // 用於存放構建FlowNetwork時的網路下標與球隊ID的對應關係 private HashMap<String, Team> teams; // 球隊雜湊表 private class Team // 球隊類 { private final int id; private final int wins; private final int loss; private final int left; public Team(int id, int wins, int loss, int left) { this.id = id; this.wins = wins; this.loss = loss; this.left = left; } } // 根據指定的檔名初始化 public BaseballElimination(String filename) { if (filename == null) throw new java.lang.IllegalArgumentException("the file name is null"); In in = new In(filename); teamNum = Integer.parseInt(in.readLine()); // 球隊數量 teams = new HashMap<String, Team>(); // 球隊雜湊表 g = new int[teamNum][teamNum]; // 最近待比對戰表 teamName = new String[teamNum]; // 隊名錶 v2id = new HashMap<Integer, Integer>(); // 球隊id與下標對照表 int id = 0; while (in.hasNextLine()) { String readLine = in.readLine().trim(); // 讀取當前行 String[] tokens = readLine.split(" +"); String key = tokens[0]; // 隊名 int wins = Integer.parseInt(tokens[1]); int loss = Integer.parseInt(tokens[2]); int left = Integer.parseInt(tokens[3]); if (!teams.containsKey(key)) { teamName[id] = key; teams.put(key, new Team(id, wins, loss, left)); for (int i = 0; i < teamNum; i++) // 最近對戰 g[id][i] = Integer.parseInt(tokens[4+i]); id++; } } } // 球隊數量 public int numberOfTeams() { return teamNum; } // 球隊列表 public Iterable<String> teams() { return teams.keySet(); } // 檢驗隊名是否有效 private void isValid(String team) { if (team == null) throw new java.lang.IllegalArgumentException("the teamName is null"); if (!teams.containsKey(team)) throw new java.lang.IllegalArgumentException("the tameName is wrong"); } // 給定球隊team的贏球數 public int wins(String team) { isValid(team); // 檢驗隊名是否有效 return teams.get(team).wins; // team球隊贏球數 } // 給定球隊team的輸球數 public int losses(String team) { isValid(team); // 檢驗隊名是否有效 return teams.get(team).loss; // team球隊輸球數 } // 給定球隊team的未比球數 public int remaining(String team) { isValid(team); // 檢驗隊名是否有效 return teams.get(team).left; // team球隊未比球數 } // 球隊team1和team2之間的未比球數 public int against(String team1, String team2) { // 有效性檢查 isValid(team1); isValid(team2); int id1 = teams.get(team1).id; // 球隊team1的id int id2 = teams.get(team2).id; // 球隊team2的id return g[id1][id2]; } // 建立FlowNetwork類 private FlowNetwork structureFlowNetwork(String team) { Team thisTeam = teams.get(team); // 當前球隊 int thisId = thisTeam.id; // 當前球隊ID int thisTeamMostWins = thisTeam.wins + thisTeam.left; // 當前球隊最大可獲勝數 meachesTeamNum = (teamNum - 1) * (teamNum -2) / 2; // 表示比賽的節點數 V = meachesTeamNum + (teamNum - 1) + 2; // 圖中節點數 flow = 0; int indexMeaches = 1; // 用於表示新增加的比賽節點的下標(1----meachesTeamNum+1) int indexI = meachesTeamNum; // 用於表示球隊節點i的下標(meachsTeamNum+1-------meachsTeamNum+teamNum) int indexJ = indexI; // 用於表示球隊節點j的下標 int s = 0; // 源節點s的下標 int t = V-1; // 目標節點t的下標 FlowNetwork flowNetwork = new FlowNetwork(V); // 構建flowNetwork類物件 // i,j分別為Team的id for (int i = 0; i < teamNum; i++) { if (i == thisId) // 關於thisID的球隊的flownetwork不會出現關於thisId的節點 continue; indexI++; // 球隊節點i的下標 indexJ = indexI; // 球隊節點j的下標 if (thisTeamMostWins < wins(teamName[i])) // 情景1 thisID的球隊的最大可能獲勝數 < 球隊i的當前獲勝數 return null; for (int j = i + 1; j < teamNum; j++) { if (j == thisId) // 關於thisID的球隊的flownetwork不會出現關於thisId的節點 continue; indexJ++; // 球隊節點j的下標 flow = flow + g[i][j]; // 流 flowNetwork.addEdge(new FlowEdge(s, indexMeaches, g[i][j])); // 新增關於比賽節點到源節點s的邊 flowNetwork.addEdge(new FlowEdge( indexMeaches, indexI, Double.POSITIVE_INFINITY)); // 新增比賽節點到對應的球隊節點i之間的邊 flowNetwork.addEdge(new FlowEdge( indexMeaches, indexJ, Double.POSITIVE_INFINITY)); // 新增比賽節點到對應的球隊節點j之間的邊 indexMeaches++; } v2id.put(indexI, i); // 網路下標與球隊ID的對應關係 flowNetwork.addEdge(new FlowEdge( indexI, t, thisTeamMostWins-wins(teamName[i]))); // 新增球隊節點i到目標節點s之間的邊 } return flowNetwork; } // 球隊team是否在數學上被淘汰 public boolean isEliminated(String team) { isValid(team); FlowNetwork gFlowNetwork = structureFlowNetwork(team); if (gFlowNetwork == null) // 情形1 return true; else // 情形2 { FordFulkerson fordFulkerson = new FordFulkerson(gFlowNetwork, 0, V-1); return flow > fordFulkerson.value(); } } // 消除給定團隊的子集R 如果未消除,則為空 public Iterable<String> certificateOfElimination(String team) { isValid(team); if (!isEliminated(team)) // team未被淘汰 return null; else // team被淘汰 { Queue<String> certificates = new Queue<>(); // 存放被消除子集 int thisId = teams.get(team).id; // 當前球隊ID FlowNetwork flowNetwork = structureFlowNetwork(team); // 構建關於team的flowNetwork if (flowNetwork == null) // 情景1 { int thisTeamMostWins = wins(team) + remaining(team); // 當前球隊最大可獲勝數 for (int i = 0; i < teamNum; i++) { if (i == thisId) continue; if (thisTeamMostWins < wins(teamName[i])) certificates.enqueue(teamName[i]); // 入棧 } } else // 情景2 { FordFulkerson fordFulkerson = new FordFulkerson(flowNetwork, 0, V-1); for (int i = 1 + meachesTeamNum; i < V; i++) // 球隊節點 { if (fordFulkerson.inCut(i)) { int id = this.v2id.get(i); // 網路下標為i的球隊的id certificates.enqueue(teamName[id]); } } } return certificates; } } }