[SMOJ220]太空飞行计划
来源:互联网 发布:老版本的知乎 ios 编辑:程序博客网 时间:2024/05/17 04:53
跟之前做的几道二分图匹配不同,从这题开始,我们要试着将问题转化为最小割,再最终转化为求最大流。
根据题意,净收益=所选实验得到的总资助-配置所选实验仪器的总花费。也可以转化为净收益=可以得到的总资助-不选实验失去的资助-配置所选实验仪器的总花费。显然,可以得到的总资助是一定的。要使净收益最大,就要使不选实验失去的资助+所选实验仪器的总花费尽可能小。
建模流程:
- 构造一个图,顶点有每个实验和实验仪器 以及一个源点
s 和汇点t - 从
s 出发,向每个实验Ei 引出一条容量为Pi 的有向边 - 从每个仪器
Ij 出发,向t 引出一条容量为Ck 的有向边 - 每个实验分别向所需的仪器引出一条容量为无穷大的有向边
然后求图的最大流,最大流即需要花费的钱。为什么这样子就可以了求出需要花费的钱?因为对于这样的网来说,图上有一点从
或者,如果把一条
根据一开始所说的,需要使失去的钱尽量少,即求最小割,于是就可以转化为最大流求解。
参考代码:
//prog82#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <sstream>using namespace std;const int MAXM = 500;const int MAXN = 500;const int INF = 0x3f3f3f3f;struct Edge { Edge *next; int cap; int dest;} edges[MAXM * MAXN], *current, *first_edge[MAXM + MAXN];int m, n, s, t;bool vis[MAXM + MAXN];Edge *counterpart(Edge *x) { return edges + ((x - edges) ^ 1);}void insert(int u, int v, int c) { current -> next = first_edge[u]; current -> cap = c; current -> dest = v; first_edge[u] = current ++;}int dfs(int u, int f) { if (u == t) return f; if (vis[u]) return 0; else vis[u] = true; for (Edge *p = first_edge[u]; p; p = p -> next) if (p -> cap) if (int res = dfs(p -> dest, min(f, p -> cap))) { p -> cap -= res; counterpart(p) -> cap += res; return res; } return 0;}int main(void) { string tmp;// ios::sync_with_stdio(false); freopen("2209.in", "r", stdin); freopen("2209.out", "w", stdout); cin >> m >> n; /*cin.get();*/ getline(cin, tmp); current = edges; //注意读掉换行符最好不要用 cin.get(),这个会因系统不同而出偏差,用 getline 代替 s = 0; t = m + n + 1; int ans = 0; fill(first_edge, first_edge + t + 1, (Edge*)0); for (int i = 1; i <= m; i++) { getline(cin, tmp);// cout << tmp << endl; stringstream ss(tmp); int money; ss >> money; ans += money; insert(s, i, money); insert(i, s, 0); int equipment; //不定量的数据输入比较麻烦,用 sstream 虽然慢了些但是方便处理 while (ss >> equipment) insert(i, equipment + m, INF), insert(equipment + m, i, 0); } for (int i = 1; i <= n; i++) { int cost; cin >> cost;// cout << cost << endl; insert(i + m, t, cost); insert(t, i + m, 0); } while (true) { memset(vis, false, sizeof vis); if (int res = dfs(s, INF)) ans -= res; else break; } //这里用到了一个技巧:最后一次增广所能到达的点就是最小割中的 S 集合,即被选的实验和仪器 for (int i = 1; i <= m; i++) if (vis[i]) cout << i << ' '; cout << endl; for (int i = 1; i <= n; i++) if (vis[i + m]) cout << i << ' '; cout << endl << ans << endl; return 0;}
阅读全文
0 0
- [SMOJ220]太空飞行计划
- 太空飞行计划
- 太空飞行计划问题
- 【网络流】太空飞行计划
- 太空飞行计划问题
- swust1737: 太空飞行计划问题
- NKOI 1937 太空飞行计划
- 太空飞行计划问题
- 太空飞行计划问题
- NKOJ1937-太空飞行计划
- 太空飞行计划问题
- 【网络流】太空飞行计划问题
- NK 2122 太空飞行计划问题
- 洛谷 P2762 太空飞行计划问题
- 太空飞行计划 最大权闭合图
- [网络流24题] 太空飞行计划
- 网络流2太空飞行计划问题
- 【网络流24题】太空飞行计划问题
- Date类
- avaScript 面向对象程序设计
- python标准类型内建函数
- Linux--系统周期性计划任务crond
- 基本JNI调用技术(c/c 与java互调
- [SMOJ220]太空飞行计划
- Apache初学
- Android JNI(实现自己的JNI_OnLoad函数)
- MongoDB GridFS 使用 存储特点
- Android JNI知识简介
- [SMOJ2207]方格取数问题
- 第三章-数据类型和运算符2
- 为什么英语学习得不到我们想要的效果?
- Inception v1 论文及源码