最近在忙项目,闲下来一天时间,继续学习Cousera上的Algorithm,这本大红书真是好用,比严某某的不知道高到那里去了,而且真心应该看英文原版。
最大流问题的本质在于寻找一条augmenting path form source to end,每找到一条augmenting path就可以使flow增加,所谓的augmenting path是一条从source 到end的无向路径,其中可以包含前向通路(forward path not full)和后向通路(backward path not empty),所以流程如下
- 利用BFS或者DFS或者最短路径算法 寻找一条送source到end的无向路径(undirected path)
- 检查该路径是否满足augmenting path的要求,如满足,则循路径方向increase forward path decrease backward path并寻找其中的瓶颈,
- 如此往复直到没有augmenting path 得出最后的Maxflow
- MinCut可以从Source出发,寻找与之相连并且forward path not full,backward path not empty的点即可
本次课程的编程作业是来计算棒球比赛赛程进行一段时间后,是否有球队因为成绩太差,无论后期如何,都会提前出局。
主要的思想在于建立一个剩余比赛的网络,然后求其最大流及相应割集,割集中的节点就是导致该响应队伍出局的原因。难点在于如何形成network,解MAxflow可以直接调用函数库
import edu.princeton.cs.algs4.Bag;
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.ST;
import edu.princeton.cs.algs4.StdOut;
public class BaseballElimination {
private final int[] w;
private final int[] l;
private final int[] r;
private final int[][] g;
private final ST<String, Integer> teams;
private final ST<Integer,String> reverseInt;
private final int N;
private final boolean[] isElimated;
private final Bag<String>[] subsets;
@SuppressWarnings("unchecked")
public BaseballElimination(String filename){
// create a baseball division from given filename in format specified below
In in = new In(filename);
N = in.readInt();
w = new int[N];
l = new int[N];
r = new int[N];
reverseInt = new ST<Integer,String>();
isElimated = new boolean[N];
teams = new ST<String,Integer>();
g = new int[N][N];
subsets = (Bag<String>[]) new Bag[N];
for (int q = 0; q < N; q++)
subsets[q] = new Bag<String>();
int i = 0;
while (!in.isEmpty()){
String tmp = in.readString();
teams.put(tmp,i);
reverseInt.put(i,tmp);
w[i] = in.readInt();
l[i] = in.readInt();
r[i] = in.readInt();
for(int j = 0; j < N ; j++){
g[i][j] = in.readInt();
}
i++;
}
for(int ii = 0; ii<N;ii++ ){
int sum = w[ii] + r[ii];
for(int m = 0; m < N; m++){
if(sum < w[m]){
isElimated[ii] = true;
subsets[ii].add(reverseInt.get(m));
}
}
}
for(int index = 0;index < N; index ++){
if(isElimated[index]==true) continue;
FlowNetwork flowNet = formFlowNet(index);
FordFulkerson maxflow = new FordFulkerson(flowNet, N + (N - 2) * (N - 1) /2, N + (N - 2) * (N - 1) /2 + 1);
for (int v = 0; v < N; v++) {
if(N == index) continue;
if (maxflow.inCut(v)){
isElimated[index] = true;
subsets[index].add(reverseInt.get(v));
}
}
}
}
private FlowNetwork formFlowNet(int index){
FlowNetwork flownet = new FlowNetwork(N + (N - 2) * (N - 1) /2 + 2);
int i = N;
for(int row =0;row < N && i != N + (N - 2) * (N - 1) /2; row++){
if(row == index) continue;
int col = row + 1;
for(; col < N; col++){
if(col == index) continue;
flownet.addEdge(new FlowEdge(N + (N - 2) * (N - 1) / 2,i,g[row][col]));
flownet.addEdge(new FlowEdge(i,row,Double.POSITIVE_INFINITY));
flownet.addEdge(new FlowEdge(i,col,Double.POSITIVE_INFINITY));
i++;
}
}
for(int j =0;j<N;j++){
if(j != index){
flownet.addEdge(new FlowEdge(j,N + (N - 2) * (N - 1) /2 + 1,w[index] + r[index] - w[j] ));
}
}
return flownet;
}
public int numberOfTeams(){
// number of teams
return N;
}
public Iterable<String> teams(){
// all teams
return teams.keys();
}
public int wins(String team){
// number of wins for given team
if(w == null) throw new NullPointerException();
if(!teams.contains(team)) throw new IllegalArgumentException();
return w[teams.get(team)];
}
public int losses(String team){
// number of losses for given team
if(l == null) throw new NullPointerException();
if(!teams.contains(team)) throw new IllegalArgumentException();
return l[teams.get(team)];
}
public int remaining(String team){
// number of remaining games for given team
if(r == null) throw new NullPointerException();
if(!teams.contains(team)) throw new IllegalArgumentException();
return r[teams.get(team)];
}
public int against(String team1, String team2){
// number of remaining games between team1 and team2
if(g == null) throw new NullPointerException();
if(!teams.contains(team1) || !teams.contains(team2)) throw new IllegalArgumentException();
int i = teams.get(team1);
int j = teams.get(team2);
return g[i][j];
}
public boolean isEliminated(String team){
// is given team eliminated?
if(!teams.contains(team)) throw new IllegalArgumentException();
if(isElimated == null) throw new NullPointerException();
return isElimated[teams.get(team)];
}
public Iterable<String> certificateOfElimination(String team) {
// subset R of teams that eliminates given team; null if not eliminated
if(!teams.contains(team)) throw new IllegalArgumentException();
if(!isElimated[teams.get(team)]) return null;
return subsets[teams.get(team)];
}
public static void main(String[] args) {
BaseballElimination division = new BaseballElimination(args[0]);
for (String team : division.teams()) {
if (division.isEliminated(team)) {
StdOut.print(team + " is eliminated by the subset R = { ");
for (String t : division.certificateOfElimination(team)) {
StdOut.print(t + " ");
}
StdOut.println("}");
}
else {
StdOut.println(team + " is not eliminated");
}
}
}
}