zoukankan      html  css  js  c++  java
  • 网络流 24 题汇总(LOJ 上只有 22 题???)

    太裸的我就不放代码了。。。(黑体字序号的题表示值得注意)

    1、搭配飞行员 [LOJ#6000]

    二分图最大匹配。

    2、太空飞行计划 [LOJ#6001]

    最小割常规套路、输出方案。(注:这题换行符要用

    3、最小路径覆盖 [LOJ#6002]

    网上大多数题解都是二分图相关的,但这题有一个更直观的做法。

    我们限制每个点的流量上下界都为 (1),从源点向每个点的“入点”连容量为 (1) 的边,从每个点的“出点”向汇点连容量为 (1) 的边,然后跑最小流。

    最后输出方案暴力 dfs 即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
    	if(Head == Tail) {
    		int l = fread(buffer, 1, BufferSize, stdin);
    		Tail = (Head = buffer) + l;
    	}
    	return *Head++;
    }
    int read() {
    	int x = 0, f = 1; char c = Getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    	return x * f;
    }
    
    #define maxn 410
    #define maxm 136010
    #define oo 2147483647
    
    int at[maxn];
    int CntP;
    struct Point {
    	int id;
    	Point(): id(0) {}
    	int p() { return id ? id : id = ++CntP; }
    } In[maxn], Out[maxn], S, T, SS, TT;
    
    struct Edge {
    	int from, to, flow;
    	Edge() {}
    	Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
    };
    struct Dinic {
    	int n, m, s, t, head[maxn], nxt[maxm];
    	Edge es[maxm];
    	int Q[maxn], hd, tl, vis[maxn];
    	int cur[maxn];
    	bool CanPass, etag[maxm];
    	int cntp, path[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c) {
    		es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		memset(vis, 0, sizeof(vis));
    		vis[t] = 1;
    		hd = tl = 0; Q[++tl] = t;
    		while(hd < tl) {
    			int u = Q[++hd];
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(!CanPass && etag[i]) continue;
    				if(!vis[e.from] && e.flow) {
    					vis[e.from] = vis[u] + 1;
    					Q[++tl] = e.from;
    				}
    			}
    		}
    		return vis[s] > 1;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return a;
    		int flow = 0, f;
    		for(int& i = cur[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(!CanPass && etag[i]) continue;
    			if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t, bool canpass) {
    		s = _s; t = _t; CanPass = canpass;
    		int flow = 0;
    		while(BFS()) {
    			rep(i, 1, n) cur[i] = head[i];
    			flow += DFS(s, oo);
    		}
    		return flow;
    	}
    	
    	void getpath(int u) {
    		path[++cntp] = at[u];
    		for(int i = head[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(e.flow < oo && at[e.to]) getpath(Out[at[e.to]].p());
    		}
    		return ;
    	}
    	void print(int s) {
    		int cnt = 0;
    		for(int i = head[s]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(!e.flow && e.to != t) {
    				cnt++;
    				cntp = 0; getpath(Out[at[e.to]].p());
    				rep(i, 1, cntp) printf("%d%c", path[i], i < cntp ? ' ' : '
    ');
    			}
    		}
    		printf("%d
    ", cnt);
    		return ;
    	}
    } sol;
    
    int main() {
    	int n = read(), m = read();
    	sol.init();
    	rep(i, 1, n)
    		sol.AddEdge(SS.p(), Out[i].p(), 1), sol.AddEdge(In[i].p(), TT.p(), 1),
    		sol.AddEdge(S.p(), In[i].p(), 1), sol.AddEdge(Out[i].p(), T.p(), 1),
    		at[In[i].p()] = at[Out[i].p()] = i;
    	sol.etag[sol.m] = sol.etag[sol.m^1] = 1;
    	sol.AddEdge(T.p(), S.p(), oo);
    	rep(i, 1, m) {
    		int a = read(), b = read();
    		sol.AddEdge(Out[a].p(), In[b].p(), oo);
    	}
    	sol.setn(CntP);
    	
    	sol.MaxFlow(SS.p(), TT.p(), 1);
    	sol.MaxFlow(T.p(), S.p(), 0);
    	sol.print(S.p());
    	
    	return 0;
    }
    

    4、魔术球 [LOJ#6003]

    二分答案(答案不超过 (2000)),然后和上一题基本一样。(注:这题不能用 fread()

    5、圆桌聚餐 [LOJ#6004]

    二分图匹配、输出方案。

    6、最长递增子序列 [LOJ#6005]

    先 dp 出 (f_i) 表示以第 (i) 个数结尾的最长不降子序列长度,然后对于 (∀(i, j)) 满足 (i < j, f_i + 1 = f_j, A_i le A_j),在第 (i) 个数和第 (j) 个数之间连边,然后点限制流量为 (1)(第三问把第一个和第 (n) 个节点的流量限制改成无穷),跑最大流。

    7、试题库 [LOJ#6006]

    同第 (5) 题。注意这题有可能有某个类型须要 (0) 道题。

    8、方格取数 [LOJ#6007]

    将棋盘黑白染色后跑最小割。

    9、餐巾计划 [LOJ#6008]

    有下界的最小费用可行流,详见这里(网上许多做法似乎没这个直观,当然他们是做了优化)。

    10、数字梯形 [LOJ#6010]

    最小费用最大流裸题。

    11、运输问题 [LOJ#6011]

    最小费用最大流裸题。

    12、分配问题 [LOJ#6012]

    同上。

    13、负载平衡 [LOJ#6013]

    小于平均值的仓库向汇点连容量为平均值减仓库存量的边,源点向大于平均值的仓库连容量为库存减平均值的边(费用均为 (0)),然后相邻仓库连容量无穷费用为 (1) 的双向边。最后跑最小费用最大流。

    14、最长 k 可重区间集 [LOJ#6014]

    这个题有点厉害啊,想了半天。。。

    还是有一个直接的思路。把坐标离散化后,最后的收益相当于每段小区间的长度乘它被覆盖的次数的总和。对于一个给出的开区间,我们可以用“环”的性质保证它出了 (1),最后能够回来 (1)。就是说我们将所有点从左到右依次连边(容量为 (k),费用为负的区间长度,这里的区间长度就是它和下一个点的距离),然后对于一个区间 ((l, r)),连一条从点 (r) 到点 (l),容量为 (1),费用为 (0) 的边,最后跑最小费用可行流。(注意这个图是有负环的,我们可以先强行流满所有的负边,然后用类似有下界可行流的办法进行调整)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 1510
    #define maxm 3014
    #define oo 2147483647
    
    struct Edge {
    	int from, to, flow, cost;
    	Edge() {}
    	Edge(int _1, int _2, int _3, int _4): from(_1), to(_2), flow(_3), cost(_4) {}
    };
    struct ZKW {
    	int n, m, s, t, cost, ans, head[maxn], nxt[maxm];
    	Edge es[maxm];
    	bool inq[maxn];
    	int d[maxn], Q[maxn*10], hd, tl;
    	bool vis[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c, int d) {
    		es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		rep(i, 1, n) d[i] = oo;
    		d[t] = 0;
    		hd = tl = 0; Q[++tl] = t; inq[t] = 1;
    		while(hd < tl) {
    			int u = Q[++hd]; inq[u] = 0;
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(d[e.from] > d[u] + e.cost && e.flow) {
    					d[e.from] = d[u] + e.cost;
    					if(!inq[e.from]) inq[e.from] = 1, Q[++tl] = e.from;
    				}
    			}
    		}
    		if(d[s] == oo) return 0;
    		cost = d[s];
    		return 1;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return ans += cost * a, a;
    		if(vis[u]) return 0;
    		vis[u] = 1;
    		int flow = 0, f;
    		for(int i = head[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(d[e.to] == d[u] - e.cost && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0, f;
    		while(BFS())
    			do {
    				memset(vis, 0, sizeof(vis));
    				f = DFS(s, oo);
    				flow += f;
    			} while(f);
    		return flow;
    	}
    } sol;
    
    #define pii pair <int, int>
    #define x first
    #define y second
    #define mp(x, y) make_pair(x, y)
    
    pair <int, int> line[maxn];
    int num[maxn], cntn;
    
    int main() {
    	int n = read(), k = read();
    	rep(i, 1, n) {
    		int l = read(), r = read();
    		if(l > r) swap(l, r);
    		line[i] = mp(l, r);
    		num[++cntn] = l; num[++cntn] = r;
    	}
    	sort(num + 1, num + cntn + 1);
    	cntn = unique(num + 1, num + cntn + 1) - num - 1;
    	rep(i, 1, n)
    		line[i].x = lower_bound(num + 1, num + cntn + 1, line[i].x) - num,
    		line[i].y = lower_bound(num + 1, num + cntn + 1, line[i].y) - num;
    	
    	int S = cntn + n + 1, T = S + 1, sum = (num[cntn] - num[1]) * k;
    	sol.init(); sol.setn(T);
    	sol.AddEdge(S, cntn, k, 0); sol.AddEdge(1, T, k, 0);
    	rep(i, 2, cntn) sol.AddEdge(i, i - 1, k, num[i] - num[i-1]);
    	rep(i, 1, n) sol.AddEdge(line[i].y, line[i].x, 1, 0);
    	sol.MaxFlow(S, T);
    	printf("%d
    ", sum - sol.ans);
    	
    	return 0;
    }
    

    15、星际转移 [LOJ#6015]

    这题其实应该给出一个条件:天数不会超过 (30)。那就枚举答案然后分层建图网络流检验。

    16、孤岛营救问题 [LOJ#6121]

    这题网络流怎么做?!

    bfs 做法显然。令状态 ((x, y, s)) 表示身处 ((x, y)) 格子,当前有的钥匙集合为 (s),然后就搜就行了。

    17、航空路线问题 [LOJ#6122]

    (2)(n - 1) 号城市限流为 (1)(1)(n) 号城市限流为 (2),所有城市费用为 (-1),跑最小费用最大流,若最大流为 (2) 则有界,沿着流输出。

    18、汽车加油行驶问题 [LOJ#6223]

    这题也许是告诉我们费用流可以用来跑最短路吧。。。

    令状态 ((x, y, k)) 表示在坐标 ((x, y)) 处,当前有 (k) 的油量。跑最短路即可。

    19、深海机器人问题 [LOJ#6224]

    最小费用最大流裸题。

    20、火星探险问题 [LOJ#6225]

    最小费用最大流裸题 + 输出方案。

    21、骑士共存问题 [LOJ#6226]

    同样是棋盘染色 + 最小割。

    22、最长k可重线段集问题 [LOJ#6227]

    这题和第 (14) 题很像,做法也一样,但是区间的权值变化了,不难处理。

  • 相关阅读:
    PHP调用WCF提供的方法
    关于git报 warning: LF will be replaced by CRLF in README.md.的警告的解决办法
    vue中引入mui报Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them的错误
    微信小程序报Cannot read property 'setData' of undefined的错误
    Vue那些事儿之用visual stuido code编写vue报的错误Elements in iteration expect to have 'v-bind:key' directives.
    关于xampp中无法启动mysql,Attempting to start MySQL service...的解决办法!!
    PHP的环境搭建
    新手PHP连接MySQL数据库出问题(Warning: mysqli_connect(): (HY000/1045): Access denied for user 'root'@'localhost' (using password: YES))
    手机号码、获得当前时间,下拉框,填写限制
    团队作业(五):冲刺总结
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7965713.html
Copyright © 2011-2022 走看看