初学网络流。存一下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算法的更多相关文章

  1. [知识点]网络流之Dinic算法

    // 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html      ...

  2. [无效]网络流之Dinic算法

    // 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html UPDA ...

  3. 网络流 之 dinic算法

    我觉得这个dinic的算法和之前的增广路法差不多 .使用BFS对残余网络进行分层,在分层时,只要进行到汇点的层次数被算出即可停止, 因为按照该DFS的规则,和汇点同层或更下一层的节点,是不可能走到汇点 ...

  4. 网络流 之 dinic 算法

    网络流指的是:网络流(network-flows)是一种类比水流的解决问题方法.(类似于水管群,有一个源点(水无限多),和一个汇点,最大流就代表这个点水管群(边集)每秒最大能送道汇点的水量) 这个怎么 ...

  5. Secret Milking Machine POJ - 2455 网络流(Dinic算法---广搜判断+深搜增广)+时间优化+二分

    题意: 第一行输入N M C ,表示从1到N有M条无向边,现在要从1走到N 走C次完全不同的路径,求最长边的最小值.下面M行是从a点到b点的距离. 建图: 题上说从两点之间可以有多条边,问的是从1~N ...

  6. 网络流(dinic算法)

    洛谷p3376 https://www.luogu.com.cn/problem/P3376 #include <iostream> #include <cstdio> #in ...

  7. 网络流最大流——dinic算法

    前言 网络流问题是一个很深奥的问题,对应也有许多很优秀的算法.但是本文只会讲述dinic算法 最近写了好多网络流的题目,想想看还是写一篇来总结一下网络流和dinic算法以免以后自己忘了... 网络流问 ...

  8. 网络流入门—用于最大流的Dinic算法

    "网络流博大精深"-sideman语 一个基本的网络流问题 最早知道网络流的内容便是最大流问题,最大流问题很好理解: 解释一定要通俗! 如右图所示,有一个管道系统,节点{1,2,3 ...

  9. Dinic算法(研究总结,网络流)

    Dinic算法(研究总结,网络流) 网络流是信息学竞赛中的常见类型,笔者刚学习了最大流Dinic算法,简单记录一下 网络流基本概念 什么是网络流 在一个有向图上选择一个源点,一个汇点,每一条边上都有一 ...

随机推荐

  1. windows 2008 r2或win7安装SP1补丁,安装sqlserver 2012

    说明:安装sql server 2012时,win7和win2008r2系统都需要打sp1补丁. 1.SP1补丁下载地址(建议用迅雷下载): http://download.microsoft.com ...

  2. MySQL 实现字符串换行

    target_describe字段值中包含 :[ 这两个特殊的字符 ,想要在字符之间加换行 需要插入CHAR(10) ),'[')) UPDATE ew_pm_project_red_detail S ...

  3. 初学Android,创建,启动,停止Service(五十八)

    Service跟Windows系统里的服务概念差不多,都在后台执行,它跟Activity的最大区别就是,它是无界面的 开发Service与开发Activity的步骤类似 1.定义一个继承Service ...

  4. JAVA常量介绍

    常量: 在程序执行过程中,其值不发生改变的量: 1.分类:     字面值常量和自定义常量: 1.字面值常量有以下几种: 字符串常量.小数常量.整数常量.字符常量.布尔常量(true.false).空 ...

  5. JavaScript中var a=b=c=d的发现

    看了别人的博客随手记录下 先看一下以下的代码 var a=1,b=2,c=3; (function(){ var a=b=1; })(); console.log(a); console.log(b) ...

  6. Flash图表控件FusionCharts如何高亮显示数据

    使用Flash图表控件FusionCharts时,通过改变alpha值是高亮显示数据的最简单方式. XML代码如下: <chart> <set label='John' value= ...

  7. ArcServer10.1系列产品之ArcGIS Web Adaptor (IIS)

    1.关于 ArcGIS Web Adaptor 通过 ArcGIS Web Adaptor,可以将 ArcGIS for Server 与您现有的 Web 服务器进行集成.ArcGIS Web Ada ...

  8. WinForm form属性

    一.布局 Autostroll   控件内容大于可见区域是否自动显示滚动条 Maximumsize 窗体可调到最大尺寸 minimumsize  窗体可调到最小尺寸 size  窗体看到的尺寸 Sta ...

  9. WEB网页如何让背景图片跟随可视窗口自适应大小

    HTML代码 <body id="body"> <div class="info-wrapper"> <div class=&qu ...

  10. LeetCode House Robber 家庭劫犯(dp)

    题意:有一个整数序列,从中挑出一些数字,使得总和是最大,前提是,相邻的两个数字中只能挑其一.比如1 2 3 就只能挑2或者1和3. 思路:很直观的题,dp思想.降低规模,从小规模开始考虑.如果只有两个 ...