网络流学习记录
来源:互联网 发布:智联招聘java简历模板 编辑:程序博客网 时间:2024/05/22 02:13
NOI2006最大获利
最大权闭合子图模板题。大概意思就是存在一个正权值点集
1. 连接
2. 连接
3. 连接
设最小割为
#include <bits/stdc++.h>using namespace std;struct node { int to, next, dis, neg;}edge[1000005];int head[200005], top = 0;void push(int i, int j, int d){ edge[++top].to = j; edge[top].dis = d; edge[top].next = head[i]; head[i] = top; edge[top].neg = top+1; edge[++top].to = i; edge[top].dis = 0; edge[top].next = head[j]; head[j] = top; edge[top].neg = top-1;}int n, m;int lev[200005], vis[200005], bfstime = 0;queue<int> que;int S, T;void dfs_out(int nd, int tab );bool bfs(){ vis[S] = ++bfstime; lev[S] = 1; que.push(S); int to, d; while (!que.empty()) { int nd = que.front(); que.pop(); for (int k = head[nd]; k; k = edge[k].next) if (to = edge[k].to, vis[to] != bfstime && edge[k].dis){ vis[to] = bfstime; lev[to] = lev[nd] + 1; que.push(to); } } //dfs_out(S, 0); return vis[T] == bfstime;}int dfs(int nd, int maxflow){ if (nd == T || !maxflow) return maxflow; int to, d, t, neg, ans = 0; //cout << nd << " " << maxflow << endl; for (int k = head[nd]; k; k = edge[k].next) if (neg = edge[k].neg, to = edge[k].to, d = edge[k].dis, d && lev[to] == lev[nd] + 1) { t = dfs(to, min(maxflow, d)); edge[k].dis -= t; edge[neg].dis += t; ans += t; maxflow -= t; } if (maxflow) lev[nd] = -1; return ans;}int dinic(){ int ans = 0; while (bfs()) ans += dfs(S, 1<<29); return ans;}void dfs_out(int nd, int tab = 0){ if (nd) { for (int i = 1; i <= tab; i++) cout << ' '; cout << nd << " -> "; for (int i = head[nd]; i; i = edge[i].next) if (edge[i].dis) cout << edge[i].to << "(" << edge[i].dis << ") "; cout << endl; for (int i = head[nd]; i; i = edge[i].next) if (edge[i].dis) dfs_out(edge[i].to, tab+2); }}int a[5005];int main(){ freopen("profit.in", "r", stdin); freopen("profit.out", "w", stdout); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); S = n+1, T = n+2; for (int i = 1; i <= n; i++) push(i, T, a[i]); n = T; int ans = 0; for (int i = 1; i <= m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); ans += c; push(++n, a, 1<<29); push(n, b, 1<<29); push(S, n, c); } cout << ans - dinic() << endl; return 0;}
Luogu2711 小行星
由于有删除考虑最小割建模。
考虑只有二维的情况:显然可以用x和y坐标的所有可能值建图,存在一对
那么三维呢?
不妨将y拆成两个点
#include <bits/stdc++.h>using namespace std;// 1->500为x,501->1000为y1,1001-1500为y2,1501-2000为zint g[2005][2005];int S = 2001, T = 2002;int n, a, b, c;int vis[2005], bfstime = 0;int lev[2005];queue<int> que;bool bfs(){ vis[S] = ++bfstime; lev[S] = 1; for (que.push(S); !que.empty(); ) { int t = que.front(); que.pop(); for (int k = 1; k <= 2002; k++) { if (!g[t][k] || vis[k] == bfstime) continue; vis[k] = bfstime; lev[k] = lev[t] + 1; que.push(k); } } return vis[T] == bfstime;}int dfs(int nd, int maxflow = INT_MAX){ if (nd == T || !maxflow) return maxflow; int t, ans = 0; for (int k = 1; k <= 2002; k++) { if (!g[nd][k] || lev[k] != lev[nd] + 1) continue; t = dfs(k, min(maxflow, g[nd][k])); ans += t; maxflow -= t; g[nd][k] -= t; g[k][nd] += t; } if (maxflow) lev[nd] = -1; return ans;}int dinic(){ int ans = 0; while (bfs()) { ans += dfs(S); } return ans;}int main(){ memset(g, 0, sizeof g); memset(vis, 0, sizeof vis); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d%d%d", &a, &b, &c); g[S][a] = g[1500+c][T] = 1; g[a][500+b] = g[1000+b][1500+c] = 1<<20; g[500+b][1000+b] = 1; } cout << dinic() << endl; return 0;}
luogu1402酒店之王
和上一题一样..
#include <bits/stdc++.h>using namespace std;// template......// 1->100是房间,101->200是客人,201->300是客人2,之后是饭233int main(){ int n, p, q; scanf("%d%d%d", &n, &p, &q); memset(g, 0, sizeof g); for (int i = 1; i <= n; i++) for (int j = 1; j <= p; j++) { int a; scanf("%d", &a); if (a) g[S][j] = 1, g[j][100+i] = 1<<20; } for (int i = 1; i <= n; i++) for (int j = 1; j <= p; j++) { int a; scanf("%d", &a); if (a) g[300+j][T] = 1, g[200+i][300+j] = 1<<20; } for (int i = 1; i <= n; i++) g[100+i][200+i] = 1; cout << dinic() << endl; return 0;}
SCOI2007 修车
第一道非模板费用流题!
费用流模型的建立往往通过最大流限制“完成任务的方式”,用费用完成最小化,比起最大流来说灵活性更大。
考虑这道题:不妨先用hzc神犇的“化动态为静态”的思维方式考虑计算“不计等待”的最小时间和:
S→Workeri,size=+∞,cost=0 Workeri→Carj,size=1,cost=timeij Carj→T,size=1,cost=0
这些条件分别限制了:每个工人修若干辆车,每辆车被修一次,最小化总时间。如何表示顺序呢?不妨将每一个工人拆成若干个“子工人”,
S→Workerik,size=1,cost=0 注:一个拆开后的工人只能修一辆车Workerik→Carj,size=1,cost=k×timeij
为什么是
#include <bits/stdc++.h>using namespace std;int g[605][605], c[605][605], inp[70][10];int n, m;int vis[605], dis[605], pre[605];queue<int> que;int S = 601, T = 602;int spfa(int &cost){ memset(dis, 127/3, sizeof dis); vis[S] = 1, dis[S] = 0; for (que.push(S); !que.empty(); ) { int t = que.front(); que.pop(); vis[t] = 0; for (int i = 1; i <= 602; i++) if (g[t][i] && dis[i] > dis[t] + c[t][i]) { dis[i] = dis[t] + c[t][i]; pre[i] = t; if (!vis[i]) vis[i] = 1, que.push(i); } } if (dis[T] > 233333333) return -1; int mf = 1e8; for (int i = T; i != S; i = pre[i]) mf = min(mf, g[pre[i]][i]); for (int i = T; i != S; i = pre[i]) g[pre[i]][i] -= mf, g[i][pre[i]] += mf; cost += mf*dis[T]; return mf;}int dinic(int &cost){ int ans = 0, t; cost = 0; while ((t = spfa(cost)) > 0) ans += t; return ans;}int main(){ memset(g, 0, sizeof g); memset(c, 0, sizeof c); scanf("%d%d", &m, &n); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &inp[i][j]); for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) {// i号倒数第j个修k for (int k = 1; k <= n; k++) { g[(i-1)*n+j][m*n+k] = 1; c[(i-1)*n+j][m*n+k] = j*inp[k][i]; c[m*n+k][(i-1)*n+j] = -j*inp[k][i]; g[m*n+k][T] = 1; // 每辆车被修一次 //c[m*n+k][T] = c[m*n+k][T] = 0; } g[S][(i-1)*n+j] = 1; // 一个拆点后的修理员只能修一辆车! } int f, cost; f = dinic(cost); printf("%.2f\n", (double)cost/n); return 0;}
k取方格数
A此题可以获得若干倍经验加成…
考虑用费用流,将每一个点拆为入点和出点,考虑如下连边:
in→out,flow=∞,cost=0 in→out,flow=1,cost=−a[i]
这样构造既可以保证可以若干次经过一个点,又可以保证取点只获得一次人生的经验。
由于原图没有负权回路,而反向弧的权都是正的,因此不会有问题。
#include <bits/stdc++.h>using namespace std;const int MAXN = 4500, MAXM = 5500000;struct node { int to, next, f, c, neg;} edge[MAXM];int head[MAXN], top = 0;void push(int i, int j, int k, int l){ //cout << "Push : " << i << " " << j << endl; ++top, edge[top] = (node) { j, head[i], k, l, top+1}, head[i] = top; ++top, edge[top] = (node) { i, head[j], 0, -l, top-1}, head[j] = top;}int dis[MAXN], vis[MAXN], pre[MAXN], pre_edge[MAXN], S = 4400, T = 4401;queue<int> que;int n, m, k;bool spfa(){ memset(dis, 127/3, sizeof dis); memset(vis, 0, sizeof vis); memset(pre, 0, sizeof pre); dis[S] = 0, vis[S] = 1, que.push(S); while (!que.empty()) { int t = que.front(); que.pop(); vis[t] = 0; for (int i = head[t]; i; i = edge[i].next) { if (edge[i].f == 0 || dis[edge[i].to] <= dis[t]+edge[i].c) continue; int to = edge[i].to, d = edge[i].c; dis[to] = dis[t] + d; pre[to] = t, pre_edge[to] = i; if (!vis[to]) vis[to] = 1, que.push(to); } } return dis[T] <= 233333333;}int mcf(int &cost){ int ans = INT_MAX; for (int t = T; t != S; t = pre[t]) ans = min(ans, edge[pre_edge[t]].f); for (int t = T; t != S; t = pre[t]) edge[pre_edge[t]].f -= ans, edge[edge[pre_edge[t]].neg].f += ans; cost += dis[T]*ans; return ans;}int work(int &cost){ int ans = 0; while (spfa()) ans += mcf(cost);//, printf("%d", ans); return ans;}const int inf = 233333333;int a[101][101];inline int number(int i, int j){ return m*(i-1)*2+(j-1)*2+1;}int main(){ scanf("%d%d%d", &k, &m, &n); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { push(number(i,j), number(i,j)+1, inf, 0), push(number(i,j), number(i,j)+1, 1, -a[i][j]); if (i+1 <= n) push(number(i,j)+1, number(i+1, j), inf, 0); if (j+1 <= m) push(number(i,j)+1, number(i, j+1), inf, 0); } push(S, number(1,1), k, 0); push(number(n,m)+1, T, k, 0); int cost = 0; work(cost); cout << -cost << endl; return 0; }
- 网络流学习记录
- 网络流学习记录
- 网络流学习记录
- 基础网络学习记录
- Chromium网络栈学习记录
- Android 学习记录-网络请求
- 学习记录 有关 网络动力学
- Nodemcu网络模块学习记录
- hihoCoder 1369 网络流一·Ford-Fulkerson算法 (网络流学习#1 记录)
- hihoCoder 1393 网络流三·二分图多重匹配 (网络流学习#3 记录)
- hihoCoder 1394 : 网络流四·最小路径覆盖 (网络流学习#4 记录)
- hihoCoder 网络流五·最大权闭合子图 (网络流学习#5 记录)
- java学习记录(四)网络编程
- 网络穿透(nat-udp) 学习记录
- 网络编程基础知识学习要点记录
- 深度学习记录第二天神经网络
- Regrofit 网络请求库学习记录
- 学习记录-网络基础知识(1)
- 1.28.1
- 习题八
- opencv学习之寻找轮廓并绘制轮廓
- POJ 3253-Fence Repair(哈夫曼树-最小值优先队列)
- CentOS各种配置步骤与所涉及Linux命令
- 网络流学习记录
- batch 批处理
- Lua与C/C++的交互
- 对称的二叉树(二叉树的镜像操作)
- STL学习:set
- 2016年--放空的日子
- 顺序表应用4-2:元素位置互换之逆置算法(数据改进)
- Cygwin下安装Kaldi
- Leetcode-445. Add Two Numbers II