POJ 3204 Ikki's Story I - Road Reconstruction(最大流)

POJ 3204 Ikki‘s Story I - Road Reconstruction

题目链接

题意:给定一个有向图,求出最大流后,问哪些边增加容量后,可以使最大流增加

思路:对于一个可以增加的,必然原来就是满流,并且从源点到汇点,的一条路径上,都是还有残留容量的,这样只要从源点和汇点分别出发dfs一遍,标记掉经过点,然后枚举满流边,如果两端都是标记过的点,这个边就是可以增加的

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 505;
const int MAXEDGE = 100005;

typedef int Type;
const Type INF = 0x3f3f3f3f;

struct Edge {
	int u, v;
	Type cap, flow;
	int cnt;
	Edge() {}
	Edge(int u, int v, Type cap, Type flow) {
		this->u = u;
		this->v = v;
		this->cap = cap;
		this->flow = flow;
		this->cnt = 0;
	}
};

struct Dinic {
	int n, m, s, t;
	Edge edges[MAXEDGE];
	int first[MAXNODE];
	int next[MAXEDGE];
	bool vis[MAXNODE];
	Type d[MAXNODE];
	int cur[MAXNODE];
	vector<int> cut;

	void init(int n) {
		this->n = n;
		memset(first, -1, sizeof(first));
		m = 0;
	}
	void add_Edge(int u, int v, Type cap) {
		edges[m] = Edge(u, v, cap, 0);
		next[m] = first[u];
		first[u] = m++;
		edges[m] = Edge(v, u, 0, 0);
		next[m] = first[v];
		first[v] = m++;
	}

	bool bfs() {
		memset(vis, false, sizeof(vis));
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = true;
		while (!Q.empty()) {
			int u = Q.front(); Q.pop();
			for (int i = first[u]; i != -1; i = next[i]) {
				Edge& e = edges[i];
				if (!vis[e.v] && e.cap > e.flow) {
					vis[e.v] = true;
					d[e.v] = d[u] + 1;
					Q.push(e.v);
				}
			}
		}
		return vis[t];
	}

	Type dfs(int u, Type a) {
		if (u == t || a == 0) return a;
		Type flow = 0, f;
		for (int &i = cur[u]; i != -1; i = next[i]) {
			Edge& e = edges[i];
			if (d[u] + 1 == d[e.v] && (f = dfs(e.v, min(a, e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[i^1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}

	Type Maxflow(int s, int t) {
		this->s = s; this->t = t;
		Type flow = 0;
		while (bfs()) {
			for (int i = 0; i < n; i++)
				cur[i] = first[i];
			flow += dfs(s, INF);
		}
		return flow;
	}

	void MinCut() {
		cut.clear();
		for (int i = 0; i < m; i += 2) {
			if (vis[edges[i].u] && !vis[edges[i].v])
				cut.push_back(i);
		}
	}

	bool mark[MAXNODE][2];

	void find(int u, int tp) {
		mark[u][tp] = true;
		for (int i = first[u]; i + 1; i = next[i]) {
			int v = edges[i].v;
			if (mark[v][tp]) continue;
			if (tp == 0 && i % 2) continue;
			if (tp && i % 2 == 0) continue;
			if (edges[i^tp].cap == edges[i^tp].flow) continue;
			find(v, tp);
		}
	}
	int solve() {
		Maxflow(0, n - 1);
		memset(mark, false, sizeof(mark));
		find(0, 0);
		find(n - 1, 1);
		int ans = 0;
		for (int i = 0; i < m; i += 2)
			if (edges[i].cap == edges[i].flow && mark[edges[i].u][0] && mark[edges[i].v][1]) ans++;
		return ans;
	}
} gao;

int n, m;

int main() {
	while (~scanf("%d%d", &n, &m)) {
		gao.init(n);
		int u, v, w;
		while (m--) {
			scanf("%d%d%d", &u, &v, &w);
			gao.add_Edge(u, v, w);
		}
		printf("%d\n", gao.solve());
	}
	return 0;
}

POJ 3204 Ikki's Story I - Road Reconstruction(最大流)

时间: 2024-11-10 01:28:15

POJ 3204 Ikki's Story I - Road Reconstruction(最大流)的相关文章

POJ 3204 Ikki&#39;s Story I - Road Reconstruction 最大流关键边

题目大意:给出一个裸的最大流的图,求这个图中哪一条边的流量增大会使整个图的最大流增大. 前言:POJ400题达成~~~ 思路:真心不知道这个题用预流推进怎么做,先给写预流推进的犇们点根蜡.. 我用的是Dinic,写起来就比较轻松.模拟一下Dinic的过程,加入一条边的流量增大就会使S到T的最大流增大的充要条件是 1.S->当前边的起始节点可以在残余网络中联通 2.当前边的终止节点->T可以在参与网络中联通 这样的话,增加了这条边的流量,就会有至少一的流量从S流到T,也就是增加了整个图的最大流.

poj 3204 Ikki&#39;s Story I - Road Reconstruction

Ikki's Story I - Road Reconstruction 题意:有N个顶点和M条边N, M (N ≤ 500, M ≤ 5,000)  ,试图改变图中的一条边使得从0到N-1的流量增加:问这样的边有几条? 思路:刚最大流入门,之后一看就觉得满流的边就是答案..真是太天真了.之后看了题解,发现满流只是前提(即使满流是几次残量的叠加也是一样),还有一个条件是,该路径的最大流量只受该边影响:即可以从S和T遍历到该边的两个端点,这就是为什么之后还要dfs给点涂色的原因:涂色前要对残余网络

【POJ 3204】Ikki&#39;s Story I - Road Reconstruction

Ikki's Story I - Road Reconstruction Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 7089   Accepted: 2039 Description Ikki is the king of a small country – Phoenix, Phoenix is so small that there is only one city that is responsible fo

POJ3184 Ikki&#39;s Story I - Road Reconstruction(最大流)

求一次最大流后,分别对所有满流的边的容量+1,然后看是否存在增广路. 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 555 8 #define MAXM 11111 9 10 struct Edge{ 11 int v

POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick

简单的看了2-sat……似乎还是挺神奇的东西……等大致刷完几道题再来写总结吧! 而这道题……算是2-sat的超级入门题了吧 不过题目大意也是醉了:圆上顺序排列n个点,现要在一些点间连边,规定边只能在圆内或圆外,求有没有可能不相交 .一开始想的是嗷嗷嗷,圆上两个点的连线怎么可能有什么在圆外在圆内之分,不都是弦么?后来才知道……原来两个点的连线不是直线可以使曲线…… 判定是否相交很简单吧……看成是一条直线上四个点,那么如果e1.a<e2.a<e1.b<e2.b就相交啦…… 都说是热身题没多难

POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick (2-SAT)

题目地址:POJ 3207 找好矛盾关系,矛盾关系是(2,5)和(3,6)这两个只能一个在外边,一个在里边,利用这个矛盾关系来建图. 可以用在外边和里边来当1和0,最后判断每对是否出现矛盾. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #inc

POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick(2 - sat啊)

题目链接:http://poj.org/problem?id=3207 Description liympanda, one of Ikki's friend, likes playing games with Ikki. Today after minesweeping with Ikki and winning so many times, he is tired of such easy games and wants to play another game with Ikki. liy

POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick(2-sat)

POJ 3207 Ikki's Story IV - Panda's Trick 题目链接 题意:一个圆上顺序n个点,然后有m组连线,连接两点,要求这两点可以往圆内或圆外,问是否能构造出使得满足所有线段不相交 思路:2-sat,判断相交的建边,一个在内,一个在外,然后跑一下2-sat即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include

[2-SAT] poj 3207 Ikki&#39;s Story IV - Panda&#39;s Trick

题目链接: http://poj.org/problem?id=3207 Ikki's Story IV - Panda's Trick Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 8063   Accepted: 2969 Description liympanda, one of Ikki's friend, likes playing games with Ikki. Today after minesweep