您的位置:首页 > 其它

zkw学习笔记

2016-01-03 09:57 351 查看
原文:http://www.artofproblemsolving.com/community/c1368h1020435

关于转化

首先是1.最小费用(可行)流

最小费用最大流

建立超级源

和超级汇

,
对顶点

, 若

添加边

, 若

添加边

, 之后求从



的最小费用最大流,
如果流量等于

, 就存在可行流,
残量网络已在原图上求出.

代码:

inline void New_Graph()
{
for(int i=3;i<=con;i++)
if(e[i])
if(e[i]>0) addside(start,i,e[i],0);
else addside(i,end,-e[i],0);
else;
}


一开始脑子抽了没有理解为什么要用-ei后来黄学长跟我说ei<0 感觉自己蠢到家了。。。。。

2.最小费用最大流

最小费用(可行)流

  连边

, 所有点



, 然后直接求.

3.最小费用(可行)流中负权边的消除

直接给负权边满流,然后转换成1

inline void Begin()
{
int i,j,k,t;
for(i=3;i<=con;i++)
for(Chain *tp=Head[i];tp;tp=tp->next)
if(tp->flow&&tp->cost<0)
{
tp->pair->flow+=tp->flow;
e[i]-=tp->flow;
e[tp->u]+=tp->flow;
con_cost=tp->flow*tp->cost;
tp->flow=0;
}
}


4.最小费用最大流中负权边的消除

先连边

, 使用
(3.) 中的方法消除负权边, 使用 (1.) 中的方法求出最小费用 (可行) 流, 之后距离标号不变, 再求最小费用最大流; 注意此时增广费用不能机械使用源点的标号——应该是源点汇点标号之差.

修改顶标

其实zkw与km有相似之处 都是修改顶标来找增广路的

详细看原文:

这里使用的是连续最短路算法.
最短路算法? 为什么程序里没有 SPFA? Dijkstra? 且慢, 先让我们回顾一下图论中最短路算法中的距离标号. 定义

为点

的距离标号,
任何一个最短路算法保证, 算法结束时对任意指向顶点

、从顶点

出发的边满足

(条件1),
且对于每个

存在一个

使得等号成立
(条件2). 换句话说, 任何一个满足以上两个条件的算法都可以叫做最短路, 而不仅仅是 SPFA、Dijkstra, 算法结束后, 恰在最短路上的边满足

.

  在最小费用流的计算中, 我们每次沿

的路径增广后都不会破坏条件
1, 但是可能破坏了条件 2. 不满足条件 2 的后果是什么呢? 使我们找不到每条边都满足

新的增广路.
只好每次增广后使用 Dijkstra, SPFA 等等算法重新计算新的满足条件 2 的距离标号. 这无疑是一种浪费. KM 算法中我们可以修改不断修改可行顶标, 不断扩大可行子图, 这里也同样, 我们可以在始终满足条件 1 的距离标号上不断修改, 直到可以继续增广 (满足条件 2).

  回顾一下 KM 算法修改顶标的方法. 根据最后一次寻找交错路不成功的 DFS, 找到

,
左边的点增加

,
右边的点减少

.
这里也一样, 根据最后一次寻找增广路不成功的 DFS, 找到 $ d = \min_{i \in V, j \notin V, u_{ij} > 0} \left\{ c_{ij} - D_i + D_j } \right\}$ ,
所有访问过的点距离标号增加

. 可以证明,
这样不会破坏性质 1, 而且至少有一条新的边进入了

的子图.

  算法的步骤就是初始标号设为

,
不断增广, 如果不能增广, 修改标号继续增广, 直到彻底不能增广: 源点的标号已经被加到了

.
注意: 在程序中所有的 cost 均表示的是 reduced cost, 即

. 另外,
这个算法不能直接用于有任何负权边的图.
更不能用于负权圈的情况. 有关这两种情况的处理, 参见 (2.) 和 (3.) 中的说明.

代码:

#include <cstdio>
#include <cstring>
using namespace std;
const int maxint=~0U>>1;

int n,m,pi1,cost=0;
bool v[550];
struct etype
{
int t,c,u;
etype *next,*pair;
etype(){}
etype(int t_,int c_,int u_,etype* next_):
t(t_),c(c_),u(u_),next(next_){}
void* operator new(unsigned,void* p){return p;}
} *e[550];

int aug(int no,int m)
{
if(no==n)return cost+=pi1*m,m;
v[no]=true;
int l=m;
for(etype *i=e[no];i;i=i->next)
if(i->u && !i->c && !v[i->t])
{
int d=aug(i->t,l<i->u?l:i->u);
i->u-=d,i->pair->u+=d,l-=d;
if(!l)return m;
}
return m-l;
}

bool modlabel()
{
int d=maxint;
for(int i=1;i<=n;++i)if(v[i])
for(etype *j=e[i];j;j=j->next)
if(j->u && !v[j->t] && j->c<d)d=j->c;
if(d==maxint)return false;
for(int i=1;i<=n;++i)if(v[i])
for(etype *j=e[i];j;j=j->next)
j->c-=d,j->pair->c+=d;
pi1 += d;
return true;
}

int main()
{
freopen("costflow.in","r",stdin);
freopen("costflow.out","w",stdout);
scanf("%d %d",&n,&m);
etype *Pe=new etype[m+m];
while(m--)
{
int s,t,c,u;
scanf("%d%d%d%d",&s,&t,&u,&c);
e[s]=new(Pe++)etype(t, c,u,e[s]);
e[t]=new(Pe++)etype(s,-c,0,e[t]);
e[s]->pair=e[t];
e[t]->pair=e[s];
}
do do memset(v,0,sizeof(v));
while(aug(1,maxint));
while(modlabel());
printf("%d\n",cost);
return 0;
}


自己的可以应对负权的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
char c;
inline void read(int &a)
{
a=0;do c=getchar();while(c<'0'||c>'9');
while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}
int con=2;
int Lastart=1,Laend=2;
int start,end;
struct Chain
{
int u,cost,flow;
Chain *next,*pair;
}*Head[100001];
int e[100001];
int con_cost;
int label[1000001];
int n,m;
inline void addside(int a,int b,int flow,int cost)
{
Chain *tp=new Chain;
tp->u=b;
tp->flow=flow;
tp->cost=cost;
tp->next=Head[a];
Head[a]=tp;
tp=new Chain;
tp->u=a;
tp->flow=0;
tp->cost=-cost;
tp->next=Head[b];
Head[b]=tp;
}
inline void Begin() { int i,j,k,t; for(i=3;i<=con;i++) for(Chain *tp=Head[i];tp;tp=tp->next) if(tp->flow&&tp->cost<0) { tp->pair->flow+=tp->flow; e[i]-=tp->flow; e[tp->u]+=tp->flow; con_cost=tp->flow*tp->cost; tp->flow=0; } }inline void New_Graph()
{
for(int i=3;i<=con;i++)
if(e[i])
if(e[i]>0) addside(Lastart,i,e[i],0);
else addside(i,Laend,-e[i],0);
else;
}
bool visited[1000001];
const
int INF=1<<29;
int DFS(int u,int F)
{
if(u==Laend)return con_cost+=F*(label[end]-label[start]),F;
int res=F;
visited[u]=true;
for(Chain *tp=Head[u];tp;tp=tp->next)
if(tp->flow&&!tp->cost&&!visited[tp->u])
{
int d=DFS(tp->u,min(tp->flow,res));
res-=d;
tp->flow-=d;
tp->pair->flow+=d;
if(!res)return F;
}
return F-res;
}
inline bool updata()
{
int a,d=INF,i;
for(i=1;i<=con;i++)
if(visited[i])
for(Chain *tp=Head[i];tp;tp=tp->next)
if(tp->flow&&!visited[tp->u]&&d>tp->cost)
d=tp->cost;
if(d==INF)return false;

for(i=1;i<=con;i++)
if(visited[i])
{
label[i]+=d;
for(Chain *tp=Head[i];tp;tp=tp->next)
tp->cost-=d,tp->pair->cost+=d;
}
return true;
}
int main()
{
read(n),read(m);
start=3,con=end=n+2;
addside(Lastart,start,INF,0);
addside(end,Laend,INF,0);
int a,b,v,d;
for(int i=1;i<=m;i++)
read(a),read(b),read(v),read(d),addside(a,b,v,d);
Begin();
New_Graph();
int maxflow=0;
do
do
memset(visited,0,sizeof(visited));
while(maxflow+=DFS(Lastart,INF));
while(updata());
printf("%d %d\n",maxflow,con_cost);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: