网络流之Dinic算法
初学网络流。存一下Dinic板子。
复杂度O(n^2*m)
UVA - 1515 Pool construction
把每个草地与 S 相连,花费为dig,每个洞与 T 相连,花费为
然后对于每个两个相邻的点连一条权值为 build 的边。
求最小割,就是把草和洞分开的花费。
因为只有三种割的情况:
割S与草之间的边,那么这个草就与T相连了。所以花费需要dig。
割T与洞之间的边。同理。
割两个相邻的点之间的边。很显然,如果他们连着同一个点(源点或者汇点),那么他们是不会被割开的。
所以只有他们连着不同的点的时候,才会需要花费build割开。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue> using namespace std;
const int N = ;
const int maxn = N*N++;
const int maxm = maxn**;
const int INF=0x3f3f3f3f;
int g[N][N];
int n,m,dig,fil,bui;
int S, T;
int ans = ; struct Dinic{
int head[maxn],Next[maxm],to[maxm],cap[maxm],flow[maxm];
int sz,n,m,s,t;
bool vis[maxn];
int cur[maxn],d[maxn];
void init(int n){
this->n=n;
memset(head,-,sizeof(head));
this->sz=-;
}
void add_edge(int a,int b,int c){
++sz;
to[sz]=b;
cap[sz]=c;flow[sz]=;
Next[sz]=head[a];head[a]=sz;
++sz;
to[sz]=a;
cap[sz]=c;flow[sz]=c;
Next[sz]=head[b];head[b]=sz;
}
bool BFS(){
memset(vis,,sizeof(vis));
queue<int>Q;
vis[s]=;
d[s]=;
Q.push(s);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=head[u];i!=-;i=Next[i]){
int v=to[i];
if(!vis[v]&&cap[i]>flow[i]){
vis[v]=;
d[v]=d[u]+;
Q.push(v);
}
}
}
return vis[t];
}
int DFS(int x,int a){
if(x==t||a==)return a;
int Flow=,f;
for(int& i=cur[x];i!=-;i=Next[i]){
int v=to[i];
if(d[v]==d[x]+&&(f=DFS(v,min(a,cap[i]-flow[i])))>){
Flow+=f;
flow[i]+=f;
flow[i^]-=f;
a-=f;
if(a==)break;
}
}
return Flow;
}
int Maxflow(int s,int t){
this->s=s,this->t=t;
int Flow=;
while(BFS()){
for(int i=;i<=n;i++)
cur[i]=head[i]; Flow+=DFS(s,INF);
}
return Flow;
}
}dinic; inline int id(int x, int y)
{
return (x-)*m + y;
} int main()
{
int t;
scanf("%d", &t);
for (int ca = ; ca <= t; ca ++)
{
scanf("%d%d",&m,&n);
scanf("%d%d%d", &dig, &fil, &bui);
ans = ;
dinic.init(n*m+);
S = n*m+, T = n*m+; for (int i = ; i <= n; i++)
{
char x;
for (int j = ; j <= m; j++)
scanf(" %c", &x), g[i][j] = x=='#' ? :;
} int dx[] = {, , , -}, dy[] = {, , -, }; for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
if (i == || j == || i == n || j == m)
{
if (!g[i][j]) ans += fil, g[i][j] = ;
dinic.add_edge(S, id(i, j), INF);
}
else if (g[i][j]) dinic.add_edge(S, id(i, j), dig);
else dinic.add_edge(id(i, j), T, fil); for (int k = ; k < ; k++)
{
int Fx = i+dx[k], Fy = j+dy[k];
if (Fx < || Fx > n || Fy < || Fy > m) continue;
dinic.add_edge(id(i, j), id(Fx, Fy), bui);
}
} ans += dinic.Maxflow(S, T);
printf("%d\n", ans);
} return ;
}
模板题:CodeVS 1993 草地排水
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue> using namespace std;
const int maxn=+;
const int INF=; struct Dinic
{
int head[maxn],Next[maxn],to[maxn],cap[maxn],flow[maxn];
//cap:容量, flow:流量
int sz,n,m,s,t;
bool vis[maxn];
int cur[maxn],d[maxn]; //d:depth cur当前弧优化
void init(int nn,int mm)
{
n=nn, m=mm;
memset(head,-,sizeof(head));
sz=-; //注意 方便亦或找反向边
} void add_edge(int a,int b,int c)
{
++sz;
to[sz]=b, Next[sz]=head[a], head[a]=sz;
cap[sz]=c, flow[sz]=; ++sz;
to[sz]=a, Next[sz]=head[b];head[b]=sz;
cap[sz]=c, flow[sz]=c; //正向的增加,反向的减少
}//加双向边 bool BFS()
{
memset(vis,,sizeof(vis));
queue<int>Q;
vis[s]=;
d[s]=;
Q.push(s);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=head[u];i!=-;i=Next[i]){
int v=to[i];
if(!vis[v]&&cap[i]>flow[i]){
vis[v]=;
d[v]=d[u]+;
Q.push(v);
}
}
}
return vis[t];
}//求深度 int DFS(int x,int a){
if(x==t||a==)return a;//当前增广路上的最小残量
int Flow=,f;
for(int& i=cur[x];i!=-;i=Next[i]){
int v=to[i];
if(d[v]==d[x]+&&(f=DFS(v,min(a,cap[i]-flow[i])))>){
Flow+=f;
flow[i]+=f;
flow[i^]-=f;//
a-=f;
if(a==)break;
}
}
return Flow;
}//增广路 int Maxflow(int ss,int tt)
{
s=ss, t=tt;
int Flow=;
while(BFS())
{
for(int i=;i<=n;i++) cur[i]=head[i];
Flow+=DFS(s,INF);
}
return Flow;
} }dinic; int n,m;
int main()
{
scanf("%d%d",&m,&n);
dinic.init(n, m);
int a, b, c;
for(int i = ; i <= m; i++){
scanf("%d%d%d", &a, &b, &c);
dinic.add_edge(a, b, c);
}
int ans = dinic.Maxflow(, n);
cout<<ans<<endl; return ;
}
HDU - 5889 Barricade
先跑一遍最短路,然后从最短路上的边中跑最小割。
TLE代码。。。我也不知道为什么会TLE。以后再改。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue> #define mms(k, x) memset(k, (x), sizeof(k)) using namespace std;
const int maxn = +;
const int maxm = *+;
const int INF = 0x3f3f3f3f; struct Dinic
{
int head[maxm],Next[maxm],to[maxm],cap[maxm],flow[maxm];
//cap:容量, flow:流量
int sz,n,m,s,t;
bool vis[maxn];
int cur[maxn],d[maxn]; //d:depth cur当前弧优化
void init(int nn,int mm)
{
n=nn, m=mm;
mms(head, -);
sz=-; //注意 方便亦或找反向边
} void add_edge(int a,int b,int c)
{
++sz;
to[sz]=b, Next[sz]=head[a], head[a]=sz;
cap[sz]=c, flow[sz]=; ++sz;
to[sz]=a, Next[sz]=head[b];head[b]=sz;
cap[sz]=c, flow[sz]=c; //正向的增加,反向的减少
}//加双向边 bool BFS()
{
memset(vis,,sizeof(vis));
queue<int>Q;
vis[s]=;
d[s]=;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
for(int i = head[u]; i != -; i = Next[i])
{
int v = to[i];
if(!vis[v] && cap[i] > flow[i])
{
vis[v]=;
d[v]=d[u]+;
Q.push(v);
}
}
}
return vis[t];
}//求深度 int DFS(int x,int a){
if(x==t||a==)return a;//当前增广路上的最小残量
int Flow=,f;
for(int& i=cur[x];i!=-;i=Next[i]){
int v=to[i];
if(d[v]==d[x]+&&(f=DFS(v,min(a,cap[i]-flow[i])))>){
Flow+=f;
flow[i]+=f;
flow[i^]-=f;//
a-=f;
if(a==)break;
}
}
return Flow;
}//增广路 int Maxflow(int ss,int tt)
{
s=ss, t=tt;
int Flow=;
while(BFS())
{
for(int i=;i<=n;i++) cur[i]=head[i];
Flow+=DFS(s,INF);
}
return Flow;
} }dinic; int v[maxm], nxt[maxm], last[maxm], l[maxm], u[maxm];
int dis[maxn], vis[maxn];
int tot = ; void build(int x, int y, int z)
{
tot++, v[tot] = y;
nxt[tot] = last[x], last[x] = tot, l[tot] = z;
u[tot] = x;
} void init()
{
tot = , mms(last, );
} int relax(int x, int y, int tmp)
{
if (dis[x]+ < dis[y])
{
dis[y] = dis[x] + ;
return ;
}
return ;
} void SPFA(int k)
{
queue<int> q;
mms(dis, INF), mms(vis, );
q.push(k), dis[k] = , vis[k] = ; while(!q.empty())
{
int x = q.front(), y;
q.pop();
for (int i = last[x]; i; i = nxt[i])
{
int y = v[i];
if (relax(x, y, i) && !vis[y]) q.push(y), vis[y] = ;
}
vis[x] = ;
}
} int n,m;
int main()
{
int t;
scanf("%d", &t);
for (int ca = ; ca <= t; ca++)
{
init();
scanf("%d%d",&m,&n);
dinic.init(n, m);
int a, b, c;
for(int i = ; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
build(a, b, c);
build(b, a, c);
} SPFA();
for (int i = ; i <= tot; i+=)
{
int x = u[i], y = v[i], c = l[i];
if (dis[y]-dis[x] == )
dinic.add_edge(x, y, c);
else if (dis[x]-dis[y] == )
dinic.add_edge(y, x, c);
} int ans = dinic.Maxflow(, n);
printf("%d\n", ans);
}
return ;
}
网络流之Dinic算法的更多相关文章
- [知识点]网络流之Dinic算法
// 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html ...
- [无效]网络流之Dinic算法
// 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html UPDA ...
- 网络流 之 dinic算法
我觉得这个dinic的算法和之前的增广路法差不多 .使用BFS对残余网络进行分层,在分层时,只要进行到汇点的层次数被算出即可停止, 因为按照该DFS的规则,和汇点同层或更下一层的节点,是不可能走到汇点 ...
- 网络流 之 dinic 算法
网络流指的是:网络流(network-flows)是一种类比水流的解决问题方法.(类似于水管群,有一个源点(水无限多),和一个汇点,最大流就代表这个点水管群(边集)每秒最大能送道汇点的水量) 这个怎么 ...
- Secret Milking Machine POJ - 2455 网络流(Dinic算法---广搜判断+深搜增广)+时间优化+二分
题意: 第一行输入N M C ,表示从1到N有M条无向边,现在要从1走到N 走C次完全不同的路径,求最长边的最小值.下面M行是从a点到b点的距离. 建图: 题上说从两点之间可以有多条边,问的是从1~N ...
- 网络流(dinic算法)
洛谷p3376 https://www.luogu.com.cn/problem/P3376 #include <iostream> #include <cstdio> #in ...
- 网络流最大流——dinic算法
前言 网络流问题是一个很深奥的问题,对应也有许多很优秀的算法.但是本文只会讲述dinic算法 最近写了好多网络流的题目,想想看还是写一篇来总结一下网络流和dinic算法以免以后自己忘了... 网络流问 ...
- 网络流入门—用于最大流的Dinic算法
"网络流博大精深"-sideman语 一个基本的网络流问题 最早知道网络流的内容便是最大流问题,最大流问题很好理解: 解释一定要通俗! 如右图所示,有一个管道系统,节点{1,2,3 ...
- Dinic算法(研究总结,网络流)
Dinic算法(研究总结,网络流) 网络流是信息学竞赛中的常见类型,笔者刚学习了最大流Dinic算法,简单记录一下 网络流基本概念 什么是网络流 在一个有向图上选择一个源点,一个汇点,每一条边上都有一 ...
随机推荐
- 转 sqlplus/RMAN/lsnrctl 等工具连接缓慢
AIX上sqlplus /as sysdba rman target / 或者lsnrctl start时或者通过sqlplus system/oracle@orcl这样通过监听连接等方式来登陆 ...
- shell下批量除去文件名中的空格
rename 's/ /_/g' * 上述命令可以将当前文件夹内所有文件的名字中得所有空格替换为_.其中g代表所有,如果不加g,如果文件名字中有多个空格,仅替换第一个.
- 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...
- 给Eclipse设置android的SDK位置时,出现这个:This Android SDK requires Andr...ate ADT to the latest
这样的问题很好解决,一个升级ADT到指定版本或以上,另一个简单的办法是调低SDK版本 找到android-sdk-windows\tools\lib下的plugin.prop文件修改其中的版本号,改为 ...
- JavaScript中的小陷阱(不定期更新。。)
1. var scores = [1, 2, 3]; var total = 0; for (var score in scores) { total += score; } var mean = t ...
- 学JS的书籍
1.JavaScript DOM 编程艺术 [说明] 这本书最大的特点就是简明易懂,循序渐进,适合初学者,非常容易上手. 计划:三天读完 读书总结:待写 2.Javascript权威指南 特点是权威. ...
- 【虚拟机-网络IP】虚拟机配置静态 IP 以后无法连接的解决办法
问题描述 将虚拟机内部 IP 地址从动态获取改成静态 IP 以后,远程连接失败. 问题分析 Azure 虚拟机的内部 IP 默认为动态分配, 由 DHCP 服务自动分配, 在虚拟机的生命周期内, 该 ...
- selenium报错信息-- Python 中 'unicodeescape' codec can't decode bytes in position XXX: trun错误解决方案
本以为是缺少utf-8造成的错误,但是加完这个还是报错,于是在网上百度了一下是因为上传的路劲粗无偶导致的 正确的写法是把路劲中“\”变为“\\”,或者在路劲的开头加上“r”,或者在路劲的开头加上“r” ...
- JavaScript_7_运算符
1. 算术运算符 2. 赋值运算符 3. 用于字符串的+运算 如果把字符串与数字相加,结果将成为字符串 <!DOCTYPE html> <html> <head> ...
- 从SAP客户主数据里直接创建商机(Opportunity)
在SAP CRM Fiori的Account应用里,直接在Account页面创建商机: 在SAP Cloud for Customer里: 要获取更多Jerry的原创文章,请关注公众号"汪子 ...