任务链接:http://coursera.cs.princeton.edu/algs4/assignments/baseball.html
本任务的重点在于理解题目的意思,理解了意思很好编码。
这篇文章对题目意思讲解的非常好,我也是看的他的才明白的:https://blog.youkuaiyun.com/lxinyuelxy/article/details/78605333
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;
}
}
}