P1343 地震逃生(最大流板题)
P1343 地震逃生
题目描述
汶川地震发生时,四川**中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边。1号点为教室,n号点为安全地带,每条边都只能容纳一定量的学生,超过楼就要倒塌,由于人数太多,校长决定让同学们分成几批逃生,只有第一批学生全部逃生完毕后,第二批学生才能从1号点出发逃生,现在请你帮校长算算,每批最多能运出多少个学生,x名学生分几批才能运完。输入格式
第一行3个整数n,m,x(x<2^31,n<=200,m<=2000);以下m行,每行三个整数a,b,c(a1,a<>b,0描述一条边,分别代表从a点到b点有一条边,且可容纳c名学生。输出格式 两个整数,分别表示每批最多能运出多少个学生,x名学生分几批才能运完。如果无法到达目的地(n号点)则输出“Orz Ni Jinan
Saint Cow!”
输入输出样例
输入 #1 复制
6 7 7
1 2 1
1 4 2
2 3 1
4 5 1
4 3 1
3 6 2
5 6 1
输出 #1 复制
3 3
说明/提示 【注释】
比如有图
1 2 100
2 3 1
100个学生先冲到2号点,然后1个1个慢慢沿2-3边走过去
18神牛规定这样是不可以的……
也就是说,每批学生必须同时从起点出发,并且同时到达终点
思路
Edmods_kraps / Dinic / ISAP
题解一
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 205;
const int maxm = 2005;
struct Edge
{
int v,w,next;
} edge[2*maxm];
int head[maxn];
int dis[maxn]; //每次bfs 都找最短路经 进行开刀
int use[maxn];
int pre[2*maxm]; //前驱数组,⚠️ pre[x] = i ,表示的意思是,到i这个节点的上一条边是 i
int min_flow[maxn];
int n, m, x;
int k = -1;
void Add(int u, int v, int w)
{
edge[++ k] = (Edge){ v, w, head[u]}; head[u] = k;
edge[++ k] = (Edge){ u, 0, head[v]}; head[v] = k;
}
//bfs用于分层
bool bfs(int s, int e)
{
for(int i = 1; i <= n; i ++)
dis[i] = INF, use[i] = 0, min_flow[i] = INF;
dis[s] = 0;
queue<int> q;
q.push(s);
int u,v;
while(! q.empty())
{
u = q.front(); q.pop();
use[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(dis[v] > dis[u] + 1 && edge[i].w)
{
dis[v] = dis[u] + 1;
pre[v] = i;
min_flow[v] = min(min_flow[u], edge[i].w);
if(! use[v])
{
q.push(v);
use[v] = 1;
}
}
}
if(min_flow[e] != INF)
break;
}
if(min_flow[e] == INF)
return false;
//更新网络中的参与流量
int now = e;
while(now != s)
{
edge[pre[now]].w -= min_flow[e];
edge[pre[now]^1].w += min_flow[e];
now = edge[pre[now]^1].v;
}
return true;
}
int Edmonds_krap(int s, int e)
{
int mx_flw = 0;
while(bfs(s, e))
{
mx_flw += min_flow[e];
}
return mx_flw;
}
inline void init()
{
for(int i = 0; i <= n; i ++)
head[i] = -1;
k = -1;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
//freopen("T.txt","r",stdin);
cin >> n >> m >> x;
init();
int u, v, w;
for(int i = 1; i <= m; i ++)
cin >> u >> v >> w, Add(u, v, w);
int res = Edmonds_krap(1, n);
if(! res)
cout << "Orz Ni Jinan Saint Cow!\n";
else
{
cout << res << " ";
int tem = x;
tem /= res;
if(tem * res == x)
cout << tem << endl;
else
cout << tem + 1 << endl;
}
return 0;
}
题解一
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 205;
const int maxm = 2005;
struct Edge
{
int v,w,next;
} edge[2*maxm];
int head[maxn],cur[maxn];
int deep[maxn];
int n, m, x;
int k = -1;
void Add(int u, int v, int w)
{
edge[++ k] = (Edge){ v, w, head[u]}; head[u] = k;
edge[++ k] = (Edge){ u, 0, head[v]}; head[v] = k;
}
//bfs用于分层
bool bfs(int s, int e)
{
for(int i = 0; i <= n; i ++)
cur[i] = head[i], deep[i] = INF;
deep[s] = 0;
queue<int> q;
q.push(s);
int u,v;
while(! q.empty())
{
u = q.front(); q.pop();
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(edge[i].w && deep[v] == INF)
{
deep[v] = deep[u] + 1;
q.push(v);
}
}
if(deep[e] != INF)
return true;
}
return false;
}
//dfs 用于增广网
int dfs(int now, int e, int limit)
{
if(! limit || now == e) return limit;
int flow = 0, f;
for(int i = cur[now]; i != -1; i = edge[i].next)
{
if(deep[edge[i].v] == deep[now] + 1 && (f = dfs( edge[i].v, e, min( limit, edge[i].w))))
{
flow += f; //答案把这一份合理的流量加上去
limit -= f; //限制条件也要改变,,这个limit 可能被一个点的多条实用。。
edge[i].w -= f; //正逆向边也要相应的操作
edge[i^1].w += f;
cur[now] = i; //当前弧优化
if(limit == 0)
break;
}
}
return flow;
}
int Dinic(int s, int e)
{
int mx_flw = 0;
while(bfs(s, e))
mx_flw += dfs(s, e, INF);
return mx_flw;
}
inline void init()
{
for(int i = 0; i <= n; i ++)
head[i] = -1;
k = -1;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
//freopen("T.txt","r",stdin);
cin >> n >> m >> x;
init();
int u, v, w;
for(int i = 1; i <= m; i ++)
cin >> u >> v >> w, Add(u, v, w);
int res = Dinic(1, n);
if(! res)
cout << "Orz Ni Jinan Saint Cow!\n";
else
{
cout << res << " ";
int tem = x;
tem /= res;
if(tem * res == x)
cout << tem << endl;
else
cout << tem + 1 << endl;
}
return 0;
}
题解一
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define INF 1e9
const int maxn = 10005;
const int maxm = 200005;
int n, m, s, e;
int k;
struct Edge
{
int v,w,next;
} edge[2 * maxm];
int head[maxn],cur[maxn],deep[maxn];
int last[maxm];
int num[maxm]; // num 桶,用来统计每个分层的节点的数量
void Add(int u, int v, int w)
{
edge[++ k] = (Edge){ v, w, head[u]};
head[u] = k;
edge[++ k] = (Edge){ u, 0, head[v]};
head[v] = k;
}
//bfs 用于更新deep层
void bfs(int e)
{
// for(int i = 0; i <= n; i ++)
// cur[i] = head[i], deep[i] = n;
for(int i = 0; i <= m; i ++) cur[i] = head[i];
for(int i = 1; i <= n; i ++) deep[i] = n;
deep[e] = 0;
queue<int> q;
q.push(e);
int u, v, w;
while(! q.empty())
{
u = q.front(); q.pop();
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(edge[i^1].w && deep[v] == n) //正图 边存在 且 v这个节点没有被求过
{
deep[v] = deep[u] + 1;
q.push(v);
}
}
}
}
int Add_flow(int s, int e)
{
int ans = INF;
int now = e;
while(now != s)
{
ans = min(ans, edge[last[now]].w);
now = edge[last[now]^1].v;
}
now = e;
while(now != s)
{
edge[last[now]].w -= ans;
edge[last[now]^1].w += ans;
now = edge[last[now]^1].v;
}
return ans;
}
int isap(int s, int e)
{
int now = s; //从起点开始进行操作
bfs(e); //先找出来一条边 被操作的增光路
for(int i = 1; i <= n; i ++) num[deep[i]] ++;
int mx_flw = 0;
while(deep[s] < n)
{
if(now == e) //如果到达汇点直接增广,重新回到源点进行下一轮增广
{
mx_flw += Add_flow(s, e);
now = s;
}
bool has_find = 0;
for(int i = cur[now]; i != -1; i = edge[i].next)
{
if(edge[i].w && deep[now] == deep[edge[i].v] + 1)
{
has_find = 1; //做标记已经找到一种可行路径
cur[now] = i; //优化当前弧
now = edge[i].v;
last[edge[i].v] = i;
break;
}
}
if(! has_find)
{
int minn = n - 1;
for(int i = head[now]; i != -1; i = edge[i].next)
if(edge[i].w)
minn = min(minn, deep[edge[i].v]);
if( (-- num[deep[now]]) == 0) break; //gap 优化出现了断层
num[deep[now] = minn + 1] ++;
cur[now] = head[now];
if(now != s)
now = edge[last[now]^1].v;
}
}
return mx_flw;
}
void init()
{
k = -1;
memset(head, -1, sizeof(head));
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
//freopen("T.txt","r",stdin);
int st;
cin >> n >> m >> st;
init();
int u,v,w;
for(int i = 1; i <= m; i ++)
cin >> u >> v >> w, Add(u, v, w);
int cnt = isap(1, n);
if(! cnt)
cout <<"Orz Ni Jinan Saint Cow!\n";
else
{
cout << cnt << " ";
int tem = st;
tem /= cnt;
if(tem * cnt == st)
cout << tem << endl;
else
cout << tem + 1 << endl;
}
return 0;
}
P1343 地震逃生(最大流板题)的更多相关文章
- 洛谷 P1343 地震逃生
P1343地震逃生 题目描述 汶川地震发生时,四川**中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边.1号点为教室,n号点为安全地带,每 ...
- P1343 地震逃生
题目描述 汶川地震发生时,四川**中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边.1号点为教室,n号点为安全地带,每条边都只能容纳一定量 ...
- BZOJ 3931 / Luogu P3171 [CQOI2015]网络吞吐量 (最大流板题)
题面 中文题目,不解释: BZOJ传送门 Luogu传送门 分析 这题建图是显然的,拆点后iii和i′i'i′连容量为吞吐量的边,根据题目要求,111和nnn的吞吐量看作∞\infty∞. 然后用di ...
- 【luogu P1343 地震逃生】 题解
题目链接:https://www.luogu.org/problemnew/show/P1343 菜 #include <queue> #include <cstdio> #i ...
- [Luogu1343]地震逃生 最大流
题目链接:https://www.luogu.org/problem/show?pid=1343 dinic跑最大流. #include<cstdio> #include<cstri ...
- [洛谷P1343]地震逃生
题目大意:有n个点m条单向边,每条边有一个容量.现有x人要分批从1走到n,问每批最多能走多少人,分几批运完(或输出无法运完). 解题思路:一看就是网络流的题目.每批最多能走多少人,即最大流.分几批运完 ...
- 「洛谷P1343」地震逃生 解题报告
P1343 地震逃生 题目描述 汶川地震发生时,四川XX中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边.1号点为教室,n号点为安全地带, ...
- 洛谷 P10P1343 地震逃生 改错
P1343 地震逃生 题目描述 汶川地震发生时,四川**中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有\(n\)个点,\(m\)条边.1号点为教室,\ ...
- hdu Flow Problem (最大流 裸题)
最大流裸题,贴下模版 view code#include <iostream> #include <cstdio> #include <cstring> #incl ...
随机推荐
- webpack基础配置(一)
第一次写博客,有点小小的兴奋,也有一点点的慌张--- 我是一个小白,仅记录自己的学习过程,内容仅供参考,如果有问题的地方,还希望各位大牛多多指教,我菜,菜是原罪,但是我可以学-- 1.最基本的:如何使 ...
- VMware虚拟机从安装到激活再到创建虚拟机解决黑屏、卡、死机系列问题教程第二篇
第二篇:在VMware中创建一个虚拟机(黑屏死机卡在最下面简单说一下你就懂了) 1.我们要打开我们已经安装好的VMware,然后点击创建新的虚拟机 2.然后选择自定义 3.下面这个默认,直接下一步 4 ...
- 内网渗透之跨边界传输 - 反弹shell
大年初一,当然是更一篇重磅文章啦 反弹shell /bin目录下带sh的都是shell nc 1.正向连接,目标机监听自身端口,攻击机主动建立连接 目标机:nc -lvvp 端口 -e /bin/ba ...
- vue+django+webpack搭建
一.前言 最近接手了一个项目,后端是django,前端是django自带的模板,用的是jinja2,写了一段时间发现用起来特别不顺手,于是想在保持现有的模板基础上,引入vue框架,这样同事可以继续用自 ...
- Vue2.0 【第二季】第4节 Vue的生命周期(钩子函数)
目录 Vue2.0 [第二季]第4节 Vue的生命周期(钩子函数) 第4节 Vue的生命周期(钩子函数) Vue2.0 [第二季]第4节 Vue的生命周期(钩子函数) 第4节 Vue的生命周期(钩子函 ...
- 死磕Lambda表达式(三):更简洁的Lambda
我们都是阴沟里的虫子,但总还是得有人仰望星空.--<三体> 在之前的文章中介绍了Lambda表达式的基本语法和正确使用姿势,这次我来介绍一些Lambda更简洁的用法. 欢迎关注微信公众号: ...
- 公钥体系(PKI)等密码学技术基础
公钥体系(PKI)等密码学技术基础 公钥体系(Public Key Infrastructure, PKI)的一些概念 对称密码算法, 典型算法:DES, AES 加解密方共用一个密钥 加/解密速度快 ...
- Scala尾递归
递归函数应用 首先,我们来对比两个递归方法的求值步骤. 假设有方法gcd,用来计算两个数的最大公约数.下面是欧几里得算法的实现: def gcp(a: Int, b: Int): Int = if ( ...
- MySQL InnoDB表的碎片量化和整理(data free能否用来衡量碎片?)
网络上有很多MySQL表碎片整理的问题,大多数是通过demo一个表然后参考data free来进行碎片整理,这种方式对myisam引擎或者其他引擎可能有效(本人没有做详细的测试).对Innodb引擎是 ...
- python深浅拷贝&垃圾回收&上下文管理(with语句)
深浅拷贝 在Python中使用copy模块用于对象的拷贝操作. 该模块提供了两个主要的方法:浅拷贝 copy.copy() 深拷贝 copy.deepcopy() 1.浅拷贝(copy) 浅拷贝: 不 ...