网络流小结

注:因为风骨傲天习惯用\(Dfs+Dinic\),所以不会用到\(EK\)等其他形式,而预流推进等较高级的,等我学了再说吧……

一、基础知识

事实上,这一部分只会包括最大流和最小费用最大流的略解,后面会补上带上下界的。

  • 最大流:\(Bfs+Dfs\)不多说,反正不难。
  • 最小费用最大流:最短路\(+Dfs\),和上面差不多,只是改一下\(Bfs\)即可。
  • 当前弧优化:用\(cur\)记一下上一次跑哪了即可(上代码,东西都在代码里)。

最大流:

inline bool bfs()
{
    memset(d,0,sizeof(d));d[s]=1;
    queue<int> q;q.push(s);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i!=-1;i=edge[i].next)
            if(!d[edge[i].to]&&edge[i].dis)
                d[edge[i].to]=d[x]+1,q.push(edge[i].to);
    }
    return d[t]?1:0;
}
inline int dfs(int pos,int dis)
{
    if(pos==t) return dis;
    for(int i=cur[pos];i!=-1;i=edge[i].next)
    {
        cur[pos]=i;
        if(d[edge[i].to]==d[pos]+1&&edge[i].dis>0)
        {
            int data=dfs(edge[i].to,min(edge[i].dis,dis));
            if(data>0)
            {
                edge[i].dis-=data;
                edge[i^1].dis+=data;
                return data;
            }
        }
    }
    return 0;
}
inline int Dinic()
{
    int ans=0;
    while(bfs())
    {
        memcpy(cur,head,sizeof(cur));
        while(int data=dfs(s,0x3f3f3f3f))
            ans+=data;
    }
    return ans;
}

费用流:

inline bool bfs()
{
    for(int i=1;i<=n;i++) d[i]=-0x3f3f3f3f;
    memset(v,0,sizeof(v));memset(flo,0,sizeof(flo));
    queue<int> q;q.push(s);d[s]=0;v[s]=1;flo[s]=1;
    while(!q.empty())
    {
        int x=q.front(); q.pop(); v[x]=0;
        for(int i=head[x];i!=-1;i=edge[i].next)
        {
            int y=edge[i].to;
            if(edge[i].dis>0&&d[y]<d[x]+edge[i].cos)
            {
                d[y]=d[x]+edge[i].cos;
                flo[y]=flo[x]+1;
                if(!v[y]){q.push(y);v[y]=1;}
            }
        }
    }
    if(d[t]==-0x3f3f3f3f) return 0;
    else return 1;
}
int dfs(int pos,int dis)
{
    if(pos==t) return dis;
    for(int i=cur[pos];i!=-1;i=edge[i].next)
        if(flo[edge[i].to]==flo[pos]+1&&edge[i].dis!=0&&d[edge[i].to]==d[pos]+edge[i].cos)
        {
            int data=dfs(edge[i].to,min(dis,edge[i].dis));
            if(data>0)
            {
                edge[i].dis-=data;
                edge[i^1].dis+=data;
                ans_cos+=edge[i].cos*data;
                cur[pos]=i;
                return data; 
            }
        }
    return 0;
}
int dinic()
{
    int ans=0;
    while(bfs())
    {
        memcpy(cur,head,sizeof(head));
        while(int data=dfs(s,0x3f3f3f3f))
            ans+=data;
    }
    return ans;
}

二、最小割

实际上,最小割的应用很多:详见国家集训队胡伯涛论文:最小割模型在信息学中的应用

1.最大权闭合子图

​ 闭合图:对于一个有向图\(G\),存在点集合\(V\),任取点\(u\)属于\(V\)\(u\)的出边的另一个点也属于\(V\),则为闭合图。

​ 最大闭合子图,即原图每个点有点权,求原图的闭合子图中最大点权和(点权可正可负)。

​ 转化:\(S\)向所有正权点建边,容量为点权,所有负权点向\(T\)建边,容量为点权绝对值,原边容量为\(Inf\)

​ 最大权\(=\)正权和\(-\)最大流。一个通俗易懂的证明

​ 变式:\([CEOI2008]order\)(下附代码):将原边容量改为租金即可(因为租用与否仅和此工序有关)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=300010;
int n,m,sum,s,t;
int head[N],num_edge,d[N],cur[N];
struct {int next,to,dis;} edge[N*10];
inline void add(int from,int to,int dis)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].dis=dis;
    edge[num_edge].to=to;
    head[from]=num_edge;
}
inline bool bfs()
{
    memset(d,0,sizeof(d));d[s]=1;
    queue<int> q;q.push(s);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i!=-1;i=edge[i].next)
            if(!d[edge[i].to]&&edge[i].dis)
                d[edge[i].to]=d[x]+1,q.push(edge[i].to);
    }
    return d[t]?1:0;
}
inline int dfs(int pos,int dis)
{
    if(pos==t) return dis;
    for(int i=cur[pos];i!=-1;i=edge[i].next)
    {
        cur[pos]=i;
        if(d[edge[i].to]==d[pos]+1&&edge[i].dis>0)
        {
            int data=dfs(edge[i].to,min(edge[i].dis,dis));
            if(data>0)
            {
                edge[i].dis-=data;
                edge[i^1].dis+=data;
                return data;
            }
        }
    }
    return 0;
}
inline int Dinic()
{
    int ans=0;
    while(bfs())
    {
        memcpy(cur,head,sizeof(cur));
        while(int data=dfs(s,0x3f3f3f3f))
            ans+=data;
    }
    return ans;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
    n=read(),m=read();s=0,t=n+m+2;
    num_edge=-1;memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        int w=read(),c=read();sum+=w;
        add(0,i,w),add(i,0,0);
        for(int j=1;j<=c;j++)
        {
            int id=read();w=read();
            add(i,id+n,w),add(id+n,i,0);
        }
    }
    for(int i=1,w;i<=m;i++)
        w=read(),add(i+n,t,w),add(t,i+n,0);
    printf("%d",sum-Dinic());
}

三、最小路径覆盖

​ 转化:先拆点为\(v,v{'}\),原图中\(u\)\(v\)有边,连\(u,v{'}\)即可。最小路径\(=\)点数\(-\)最大匹配。

​ 变式:\([SDOI2010]\)星际竞速:考虑跳跃,无论从哪个点跳到\(i\),花费均为\(A[i]\),所以可以建\(S\)\(v{'}\),容量为\(A[i]\)的边。(下附代码)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=300010;
int n,m,sum,s,t,flo[N],v[N],ans;
int head[N],num_edge,d[N],cur[N];
struct {int next,to,dis,cos;} edge[N*10];
inline void add(int from,int to,int dis,int cos)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].dis=dis;
    edge[num_edge].cos=cos;
    edge[num_edge].to=to;
    head[from]=num_edge;
}
inline bool bfs()
{
    memset(d,0x3f3f3f3f,sizeof(d));
    memset(v,0,sizeof(v));memset(flo,0,sizeof(flo));
    queue<int> q;q.push(s);flo[s]=1;v[s]=1;d[s]=0;
    while(!q.empty())
    {
        int x=q.front();q.pop();v[x]=0;
        for(int i=head[x];i!=-1;i=edge[i].next)
            if(d[edge[i].to]>d[x]+edge[i].cos&&edge[i].dis>0)
            {
                d[edge[i].to]=d[x]+edge[i].cos;
                flo[edge[i].to]=flo[x]+1;
                if(!v[edge[i].to]) q.push(edge[i].to),v[edge[i].to]=1;
            }
    }
    return d[t]<0x3f3f3f3f?1:0;
}
inline int dfs(int pos,int dis)
{
    if(pos==t) return dis;
    for(int i=cur[pos];i!=-1;i=edge[i].next)
    {
        int y=edge[i].to;cur[pos]=i;
        if(d[y]==d[pos]+edge[i].cos&&edge[i].dis!=0&&flo[y]==flo[pos]+1)
        {
            int data=dfs(y,min(edge[i].dis,dis));
            if(data>0)
            {
                edge[i].dis-=data;
                edge[i^1].dis+=data;
                ans+=data*edge[i].cos;
                return data;
            }
        }
    }
    return 0;
}
inline int Dinic()
{
    while(bfs())
    {
        memcpy(cur,head,sizeof(cur));
        while(int data=dfs(s,0x3f3f3f3f));
    }
    return ans;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);//12
    //freopen("B.in","r",stdin);//6
    //freopen("C.in","r",stdin);//230
#endif
    n=read(),m=read();s=0,t=(n<<1)+1;
    num_edge=-1;memset(head,-1,sizeof(head));
    for(int i=1,w;i<=n;i++)
        w=read(),add(s,i+n,1,w),add(i+n,s,0,-w);
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read(),w=read();
        if(v<u) swap(u,v);
        add(u,v+n,1,w),add(v+n,u,0,-w);
    }
    for(int i=1;i<=n;i++)
        add(s,i,1,0),add(i,s,0,0),add(i+n,t,1,0),add(t,i+n,0,0);
    printf("%d",Dinic());
}

四、各种奇特的建图

1、与时间有关:

其实这样的题以前考过一次,好像那次\(Itst\)是全场唯一一个切那道题的,现在再放一道题:

传送门:\(Luogu[SCOI2007]\)修车

显然和时间有关,要分时间段建边。

分析性质,对于一个修车工,假设其修的车用时分别为:\(T_1,T_2……,T_p\),那么总等待时间为:\(T_p*1+T_{p-1}*2+……+T_1*p\)

可以看出一个修车工所修的第倒数\(k\)个车对答案的贡献为\(k*T\)。所以我们可以将每个修车工拆为\(N\)个时间段,表示倒数几个修,将每个车和拆开的点建边,费用为时间段编号乘花费时间即可。(下附代码)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=6000,M=100010;
int n,m,num_edge,s,t,ans;
int d[N],head[N],v[N],flo[N],cur[N];
struct Edge{int next,to,dis,cos;} edge[M];
inline void add(int from,int to,int dis,int cos)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].dis=dis;
    edge[num_edge].cos=cos;
    edge[num_edge].to=to;
    head[from]=num_edge;
}
inline bool bfs()
{
    memset(d,0x3f3f3f3f,sizeof(d));
    memset(v,0,sizeof(v));memset(flo,0,sizeof(flo));
    queue<int> q;q.push(s);d[s]=0,v[s]=flo[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();v[x]=0;
        for(int i=head[x];i!=-1;i=edge[i].next)
            if(d[edge[i].to]>d[x]+edge[i].cos&&edge[i].dis>0)
            {
                d[edge[i].to]=d[x]+edge[i].cos;
                flo[edge[i].to]=flo[x]+1;
                if(!v[edge[i].to]) q.push(edge[i].to),v[edge[i].to]=1;
            }
    }
    return d[t]<0x3f3f3f3f?1:0;
}
inline int dfs(int pos,int dis)
{
    if(pos==t) return dis;
    for(int i=cur[pos];i!=-1;i=edge[i].next)
    {
        int y=edge[i].to;cur[pos]=i;
        if(flo[y]==flo[pos]+1&&d[y]==d[pos]+edge[i].cos&&edge[i].dis>0)
        {
            int data=dfs(y,min(dis,edge[i].dis));
            if(data>0)
            {
                edge[i].dis-=data;
                edge[i^1].dis+=data;
                ans+=edge[i].cos*data;
                return data;
            }
        }
    }
    return 0;
}
inline int Dinic()
{
    while(bfs())
    {
        memcpy(cur,head,sizeof(head));
        while(int data=dfs(s,0x3f3f3f3f));
    }
    return ans;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);//Ans=1.50
#endif
    num_edge=-1;memset(head,-1,sizeof(head));
    m=read(),n=read();s=0,t=m*n+n+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int T=read();
            for(int k=1;k<=n;k++)
                add(i,n*j+k,1,k*T),add(n*j+k,i,0,-k*T);
        }
    for(int i=1;i<=n;i++) add(s,i,1,0),add(i,s,0,0);
    for(int i=1;i<=n*m;i++) add(i+n,t,1,0),add(t,i+n,0,0);
    printf("%.2lf",(double)Dinic()/(double)n);
}

\(To\) \(be\) \(continued...\)(怎么办我好想咕)

转载于:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11528471.html

内容概要:本文档主要介绍了Intel Edge Peak (EP) 解决方案,涵盖从零到边缘高峰的软件配置和服务管理。EP解决方案旨在简化客户的入门门槛,提供一系列工具和服务,包括Edge Software Provisioner (ESP),用于构建和缓存操作系统镜像和软件栈;Device Management System (DMS),用于远程集群或本地集群管理;以及Autonomous Clustering for the Edge (ACE),用于自动化边缘集群的创建和管理。文档详细描述了从软件发布、设备制造、运输、安装到最终设备激活的全过程,并强调了在不同应用场景(如公共设施、工业厂房、海上油井和移动医院)下的具体部署步骤和技术细节。此外,文档还探讨了安全设备注册(FDO)、集群管理、密钥轮换和备份等关键操作。 适合人群:具备一定IT基础设施和边缘计算基础知识的技术人员,特别是负责边缘设备部署和管理的系统集成商和运维人员。 使用场景及目标:①帮助系统集成商和客户简化边缘设备的初始配置和后续管理;②确保设备在不同网络环境下的安全启动和注册;③支持大规模边缘设备的自动化集群管理和应用程序编排;④提供详细的密钥管理和集群维护指南,确保系统的长期稳定运行。 其他说明:本文档是详细描述了Edge Peak技术及其应用案例。文档不仅提供了技术实现的指导,还涵盖了策略配置、安全性和扩展性的考虑,帮助用户全面理解和实施Intel的边缘计算解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值