POJ3204 最大流

求满足如下条件的边的个数:
增加该边的容量,可以使得最大流变大.
step1:求一遍最大流,如果某条边符合我们的要求,那么这条边必然是满流的,否则增加容量也没有用;
step2:对于漫流边(u->v),那么必然存在从源点到u的不饱和的路径,同样从v到汇点的不饱和的路径;



public class Main {
	public static void main(String[] args) {
		new Task().solve();
	}
}

@SuppressWarnings("unchecked")
class Task {
	InputReader in = new InputReader(System.in);
	PrintWriter out = new PrintWriter(System.out);
	
	List<Integer>[] adj , reverseAdj  ;
	List<DinicGraph.Edge> fullEdge ; 
	
	void dfs(int u , List<Integer>[] grid , boolean[] color){
		color[u] = true ;
		for(int v : grid[u]){
			if(! color[v]) dfs(v ,  grid , color) ;
		}
	}

	void solve() {
		int n = in.nextInt() ;
		int m = in.nextInt() ;
		DinicGraph graph = new DinicGraph(n) ;
		while(m-- > 0){
			int u = in.nextInt() ;
			int v = in.nextInt() ;
			long w = in.nextLong() ;
			if(w != 0)
			   graph.addEdge(u , v , w) ;
		}
		adj = new List[n] ;
		reverseAdj = new List[n] ;
		for(int i = 0 ; i < n ; i++){
			adj[i] = new ArrayList<Integer>() ;
			reverseAdj[i] = new ArrayList<Integer>() ;
		}
		fullEdge = new ArrayList<DinicGraph.Edge>() ;
		
		graph.getMaxFlow(0 , n-1) ;
		for(int u = 0 ; u < n ; u++){
			for(DinicGraph.Edge edge : graph.adj[u]){
				if(! edge.isDir) continue ;
				if(edge.flow == edge.capacity)
					fullEdge.add(edge) ;
				else{
					adj[u].add(edge.to) ;
					reverseAdj[edge.to].add(u) ;
				}	
			}
		}
		boolean[] canFromSource = new boolean[n] ;
		Arrays.fill(canFromSource , false) ;
		boolean[] canFromTarget = new boolean[n] ;
		Arrays.fill(canFromTarget , false) ;
		dfs(0, adj , canFromSource) ;
		dfs(n-1, reverseAdj , canFromTarget) ;
		int sum = 0 ;
		for(DinicGraph.Edge edge : fullEdge){
			if(canFromSource[edge.from] && canFromTarget[edge.to]) 
				sum++ ;
		}
		out.println(sum) ;
		out.flush();
	}

}

@SuppressWarnings("unchecked")
class DinicGraph {
	class Edge {
		int from, to;
		long flow, capacity;
		Edge reverse;
        boolean isDir ;
		
		Edge(int from, int to, long flow, long capacity , boolean isDir) {
			this.from = from;
			this.to = to;
			this.flow = flow;
			this.capacity = capacity;
			this.isDir = isDir ;
		}
	}

    List<Edge>[] adj;
	int N, distance[];

	DinicGraph(int N) {
		this.N = N;
		adj = new List[N];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Edge>();
		}
		distance = new int[N];
	}

    Edge addEdge(int from, int to, long capacity) {
		Edge e1 = new Edge(from, to, 0, capacity , true) ;
		Edge e2 = new Edge(to, from, 0, 0 , false) ;
		e1.reverse = e2;
		e2.reverse = e1;
		adj[from].add(e1);
		adj[to].add(e2);
		return e1;
	}

	boolean bfs(int source, int target) {
		Arrays.fill(distance, Integer.MAX_VALUE);
		distance[source] = 0;
		Queue<Integer> Q = new LinkedList<Integer>();
		Q.add(source);
		while (!Q.isEmpty()) {
			int u = Q.poll() ;
			for (Edge e : adj[u]) {
				int v = e.to;
				if (e.capacity - e.flow > 0 && distance[v] == Integer.MAX_VALUE) {
					distance[e.to] = distance[u] + 1;
					Q.add(v);
					if (v == target) {
						return true;
					}
				}
			}
		}
		return false;
	}

	public long dfs(int u, int target, long cMin) {
		if (u == target) {
			return cMin ;
		}
		for (Edge e : adj[u]) {
			int v = e.to;
			if (distance[v] != distance[u] + 1 || e.capacity - e.flow == 0) {
				continue;
			}
			long add = dfs(v, target, Math.min(cMin, e.capacity - e.flow));
			if (add == 0) {
				continue;
			}
			e.flow += add;
			e.reverse.flow -= add;
			return add;
		}
		return 0L ;
	}

	public long getMaxFlow(int source, int target) {
		long flow = 0;
		while (bfs(source, target)) {
			while (true) {
				long add = dfs(source, target, Long.MAX_VALUE);
				if (add == 0) {
					break;
				}
				flow += add;
			}
		}
		return flow;
	}
}

class InputReader {
	public BufferedReader reader;
	public StringTokenizer tokenizer;

	public InputReader(InputStream stream) {
		reader = new BufferedReader(new InputStreamReader(stream), 32768);
		tokenizer = new StringTokenizer("");
	}

	private void eat(String s) {
		tokenizer = new StringTokenizer(s);
	}

	public String nextLine() {
		try {
			return reader.readLine();
		} catch (Exception e) {
			return null;
		}
	}

	public boolean hasNext() {
		while (!tokenizer.hasMoreTokens()) {
			String s = nextLine();
			if (s == null)
				return false;
			eat(s);
		}
		return true;
	}

	public String next() {
		hasNext();
		return tokenizer.nextToken();
	}

	public int nextInt() {
		return Integer.parseInt(next());
	}

	public long nextLong() {
		return Long.parseLong(next());
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}

	public BigInteger nextBigInteger() {
		return new BigInteger(next());
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值