【模板】网络流学习笔记

(还是不熟 好难啊


HDU1532

最大流裸题

Edmonds_Karp算法(bfs)

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;


int m;
int g[220][220],pre[220];int bfs(int st,int ed)
{
    for(int i=1;i<=m;i++)pre[i]=-1;
    int u,w=inf;
    queue<int>que;
    que.push(st);pre[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        if(u==ed)break;
        for(int i=1;i<=m;i++)
        {
            if(pre[i]==-1&&g[u][i]>0)
            {
                pre[i]=u;
                w=min(w,g[u][i]);
                que.push(i);
            }
        }
    }
    if(pre[ed]==-1)return 0;
    return w;
}

int E_K(int st,int ed)
{
    int w,sum=0;
    while(w=bfs(st,ed))
    {
        int u=ed;
        while(u!=st)
        {
            g[pre[u]][u]-=w;
            g[u][pre[u]]+=w;
            u=pre[u];
        }
        sum+=w;
    }
    return sum;
}


int main()
{
    int n,i,j,k,u,v,w;
    while(~scanf("%d%d",&n,&m))
    {
        memset(g,0,sizeof(g));
        
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            g[u][v]+=w;
        }
        printf("%d
",E_K(1,m));
    }
}
 

Dinic算法 (是E_K算法的优化 可以快一些 (bfs+dfs))

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;


int m;
int g[220][220],dep[220];

bool bfs(int st,int ed)
{
    for(int i=1;i<=m;i++)dep[i]=-1;
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=1;i<=m;i++)
        {
            if(dep[i]==-1&&g[u][i]>0)
            {
                dep[i]=dep[u]+1;
                if(i==ed)return 1;
                que.push(i);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=1;i<=m;i++)
    {
        if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim))))
        {
            g[st][i]-=d;
            g[i][st]+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}

int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}


int main()
{
    int n,i,j,k,u,v,w;
    while(~scanf("%d%d",&n,&m))
    {
        memset(g,0,sizeof(g));
        
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            g[u][v]+=w;
        }
        printf("%d
",Dinic(1,m));
    }
}
View Code

LOJ网络流 24 题」搭配飞行员 (第一题

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;


int n,m;
int g[110][110],dep[110];

bool bfs(int st,int ed)
{
    for(int i=0;i<=n;i++)dep[i]=-1;
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=1;i<=n;i++)
        {
            if(dep[i]==-1&&g[u][i]>0)
            {
                dep[i]=dep[u]+1;
                if(i==ed)return 1;
                que.push(i);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=0;i<=n;i++)
    {
        if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim))))
        {
            g[st][i]-=d;
            g[i][st]+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}

int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}


int main()
{
    int i,j,k,u,v;
    scanf("%d%d",&n,&m);
//    scanf("%d",&k);
    for(i=1;i<=m;i++)g[0][i]=1;
    for(i=m+1;i<=n;i++)g[i][n+1]=1;
    n++;
//    while(k--)
    while(~scanf("%d%d",&u,&v))
    {
//        scanf("%d%d",&u,&v);
        g[u][v]=1;
        
    }
    printf("%d
",Dinic(0,n));
}
View Code

洛谷P2756飞行员配对方案问题

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;


int n,m;
int g[110][110],dep[110];

bool bfs(int st,int ed)
{
    for(int i=0;i<=n;i++)dep[i]=-1;
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=1;i<=n;i++)
        {
            if(dep[i]==-1&&g[u][i]>0)
            {
                dep[i]=dep[u]+1;
                if(i==ed)return 1;
                que.push(i);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=0;i<=n;i++)
    {
        if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim))))
        {
            g[st][i]-=d;
            g[i][st]+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}

int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}


int main()
{
    int i,j,k,u,v;
    scanf("%d%d",&m,&n);
    for(i=1;i<=m;i++)g[0][i]=1;
    for(i=m+1;i<=n;i++)g[i][n+1]=1;
    n++;
    scanf("%d%d",&u,&v);
    while(u!=-1&&v!=-1)
    {
        g[u][v]=1;
        scanf("%d%d",&u,&v);
    }
    k=Dinic(0,n);
    if(k==0)puts("No solution!");
    else
    {
        printf("%d
",k);
        for(i=1;i<=m;i++)
        {
            for(j=m+1;j<=n;j++)
            if(g[j][i]!=0)printf("%d %d
",i,j);
        }
    }
}
View Code

好艰难 我觉得我只会 对着模板抄

P3381最小费用最大流

求最大流量下的最小费用

(为了xxxxxx,尝试用链式前向星来做,还不太习惯)

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;


struct P{
    int to,flow,dis,next;
}p[50500<<1];
int head[50500<<1],pnum;

void add(int from,int to,int flow,int dis)
{
    p[++pnum].next=head[from];
    p[pnum].to=to;
    p[pnum].flow=flow;
    p[pnum].dis=dis;
    head[from]=pnum;
}


int dis[5050],vis[5050],pre[5050],last[5050],flow[5050];


bool spaf_bfs(int s,int t)
{
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(flow,inf,sizeof(flow));
    queue<int> que;
    que.push(s);dis[s]=0;pre[t]=-1;vis[s]=1;
    while(!que.empty())
    {
        int u=que.front();que.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(p[i].flow>0&&dis[p[i].to]>dis[u]+p[i].dis)
            {
                dis[p[i].to]=dis[u]+p[i].dis;
                pre[p[i].to]=u;
                last[p[i].to]=i;
                flow[p[i].to]=min(flow[u],p[i].flow);
                if(!vis[p[i].to])
                {
                    vis[p[i].to]=1;
                    que.push(p[i].to);
                }
            }
        }
    }
    return pre[t]!=-1;
}

void solve(int s,int t,int &w,int &c)
{
    w=0;c=0;
    while(spaf_bfs(s,t))
    {
        int u=t;
        w+=flow[t];
        c+=flow[t]*dis[t];
        while(u!=s)
        {
            p[last[u]].flow-=flow[t];
            p[last[u]^1].flow+=flow[t];
            u=pre[u];
        }
    }
}



int main()
{
    memset(head,-1,sizeof(head));pnum=-1;
    int n,m,s,t,i,u,v,w,f;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&u,&v,&w,&f);
        add(u,v,w,f);
        add(v,u,0,-f);
    }
    solve(s,t,u,v);
    printf("%d %d
",u,v);
}
View Code

Gasoline

最大流+二分

借着别人的博客的二分 总算补完了这一题。

二分求最小/最大值技巧还不太熟。一直没能想到。

(用E_K算法会超时,用Dinic不会)

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;

struct P{
    int next,to,flow;
}p[22200<<1];
int head[22200<<1],pnum;
struct PP{
    int u,v,t;
    PP(){}
    PP(int uu,int vv,int tt){u=uu;v=vv;t=tt;}
}pp[20200];


void add(int from,int to,int flow)
{
    p[++pnum].next=head[from];
    p[pnum].to=to;
    p[pnum].flow=flow;
    head[from]=pnum;
}

int x,y,c,n,allsum,a[2020],b[2020];

int pre[2020],dep[2020];
bool vis[2020];


bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].flow)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&(d=dfs(p[i].to,ed,min(p[i].flow,lim))))
        {
            p[i].flow-=d;
            p[i^1].flow+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}
int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}
/*
int bfs(int st,int ed)
{
    memset(vis,0,sizeof(vis));
    int u,w=inf;
    queue<int>que;
    que.push(st);pre[st]=pre[ed]=-1;vis[st]=1;
    while(!que.empty())
    {
        u=que.front();que.pop();
        if(u==ed)break;
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(vis[p[i].to]==0&&p[i].flow>0)
            {
                vis[p[i].to]=1;
                pre[p[i].to]=i;
                w=min(w,p[i].flow);
                que.push(p[i].to);
            }
        }
    }
    if(pre[ed]==-1)return 0;
    return w;
}

int E_K(int st,int ed)
{
    int w,sum=0;
    while(w=bfs(st,ed))
    {
        for(int i=pre[ed];i!=-1;i=pre[p[i^1].to])
        {
            p[i].flow-=w;
            p[i^1].flow+=w;
        }
        sum+=w;
    }
    return sum;
}*/

bool check(int mid)
{
    int i;
    memset(head,-1,sizeof(head));pnum=-1;
    for(i=1;i<=y;i++)
    {
        add(0,i,a[i]);
        add(i,0,0);
    }
    for(i=1;i<=x;i++)
    {
        add(y+i,n,b[i]);
        add(n,y+i,0);
    }
    for(i=1;i<=c;i++)
    {
        if(pp[i].t<=mid)
        {
            add(pp[i].u,pp[i].v+y,inf);
            add(pp[i].v+y,pp[i].u,0);
        }
    }
    int maxflow=Dinic(0,n);
    if(maxflow==allsum)return 1;
    return 0;
}

int main()
{
    allsum=0;
    int i,j,k,w;
    int u,v,t,l,r=0,mid,ans;
    scanf("%d%d%d",&x,&y,&c);
    n=x+y+1;
    for(i=1;i<=x;i++)
    {
        scanf("%d",&b[i]);
        allsum+=b[i];
    }
    for(i=1;i<=y;i++)scanf("%d",&a[i]);
    for(i=1;i<=c;i++)
    {
        scanf("%d%d%d",&v,&u,&t);
        pp[i]=PP(u,v,t);
        r=max(r,t);
    }
    l=0;ans=-1;r++; 
    while(l<r)
    {
        mid=(l+r)>>1;
        if(check(mid))
        {
            ans=mid;
            r=mid;
        }
        else l=mid+1;
    }
    printf("%d
",ans);
}
View Code

LOJ 「网络流 24 题」太空飞行计划 (第二题

1.初学网络流,从这道题的洛谷题解知道了一件事:

  Dinic最后一次bfs的dep(深度)数组标记了与源点连通的点(即,未被初始化标记的点 就是 与最终确定与源点连通的点),有利于最后方案的输出。

  下一题告诉我这是假的QAQ。。所以通用方法是什么/(ㄒoㄒ)/~~

2.据说 这道题是最小割的题。我用最大流做的,不懂为什么是最小割?

   

      因为:最小割==最大流

  有趣的是:一直想不到,正确建图后,总的利润-最大流的花费 会等于 最大盈利。但是按这道题的正确建图方法去思考,正好是这样!

3.这道题,据说:

  这道题数据是在windows生成的,输入数据中所有的换行都是' '而不是' '
  读入某实验需要用到的仪器编号的时候,可以这么读入

char tools[10000];
memset(tools,0,sizeof tools);
cin.getline(tools,10000);
int ulen=0,tool;
while (sscanf(tools+ulen,"%d",&tool)==1)//之前已经用scanf读完了赞助商同意支付该实验的费用
{//tool是该实验所需仪器的其中一个      
    //这一行,你可以将读进来的编号进行储存、处理,如连边。
    if (tool==0) 
        ulen++;
    else {
        while (tool) {
            tool/=10;
            ulen++;
        }
    }
    ulen++;
}

代码:

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=3e3+50;


struct P{
    int to,flow,next;
}p[maxn];
int head[maxn],pnum;

void add(int from,int to,int flow)
{
    p[++pnum].next=head[from];
    p[pnum].to=to;
    p[pnum].flow=flow;
    head[from]=pnum;
}


int dis[maxn],vis[maxn],dep[maxn],flow[maxn];


bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].flow)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}
int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&p[i].flow&&(d=dfs(p[i].to,ed,min(p[i].flow,lim))))
        {
            p[i].flow-=d;
            p[i^1].flow+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}
int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}

//这道题数据是在windows生成的
//输入数据中所有的换行都是'
'而不是'
'

int main()
{
    memset(head,-1,sizeof(head));pnum=-1;
    int m,n,i,j,k,w,ed,sum=0,ans;
    scanf("%d%d",&m,&n);
    ed=m+n+1;
    char tools[10000];//
    
    for(i=1;i<=m;i++)
    {
        scanf("%d",&w);
        sum+=w;
        add(0,i,w);
        add(i,0,0);
        memset(tools,0,sizeof tools);
        cin.getline(tools,10000);
        int ulen=0,tool;
        while (sscanf(tools+ulen,"%d",&tool)==1)//之前已经用scanf读完了赞助商同意支付该实验的费用
        {//tool是该实验所需仪器的其中一个      
            add(i,m+tool,inf);
            add(m+tool,i,0);//这一行,你可以将读进来的编号进行储存、处理,如连边。
            if (tool==0) 
                ulen++;
            else {
                while (tool) {
                    tool/=10;
                    ulen++;
                }
            }
            ulen++;
        }
    }
    for(i=1;i<=n;i++)
    {
        scanf("%d",&w);
        add(m+i,ed,w);
        add(ed,m+i,0);
    }
    ans=sum-Dinic(0,ed);
    for(i=1,k=0;i<=m;i++)
    {
        if(dep[i]!=-1)
        {
            if(k)putchar(32);
            k=1;
            printf("%d",i);
        }
    }
    putchar(10);
    for(i=m+1,k=0;i<ed;i++)
    {
        if(dep[i]!=-1)
        {
            if(k)putchar(32);
            k=1;
            printf("%d",i-m);
        }
    }
    putchar(10);
    printf("%d
",ans);
}
View Code

洛谷P2764 最小路径覆盖问题 

6002「网络流 24 题」最小路径覆盖

路径输出是一个问题啊。本来以为用if(dep[i]!=-1)来找就行了,结果发现是假的

这道题由于流量只是1,所以就用if(p[i].w==0&&i&1==0)来找,但是如果流量等于2,3,4....n呢?QAQ

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=6e3+5;

struct P{
    int to,w,next;
}p[maxn<<2];
int head[355],cnt;

void add(int u,int v,int w)
{
    p[cnt].to=v;
    p[cnt].w=w;
    p[cnt].next=head[u];
    head[u]=cnt++;
}

int n;

int dep[355];

bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].w)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
        {
            p[i].w-=d;
            p[i^1].w+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }    
    }
    return w;
}

int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}


int son[335];
bool isson[335];
void getline()
{
    int u,v,f;
    for(u=1;u<=n;u++)
    {
        f=u;
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(p[i].w||i&1)continue;
            v=p[i].to;
            if(v>n)v-=n;
            son[f]=v;f=v;
            isson[v]=1;
            p[i].w=-1;
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    
    int m,i,u,v,ed,res;
    scanf("%d%d",&n,&m);ed=n*2+1;
    for(i=1;i<=n;i++)
    {
        add(0,i,1);add(i,0,0);
        add(i+n,ed,1);add(ed,i+n,0);
    }
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,n+v,1);add(n+v,u,0);
    }
    
    res=n-Dinic(0,ed);
    
    
    getline();
    for(i=1;i<=n;i++)
    {
        if(isson[i])continue;
        u=i;
        printf("%d ",u);
        while(son[u])
        {
            u=son[u];
            printf("%d ",u);
        }
        printf("
");
    }
    printf("%d
",res);
    
}
View Code

然后

6003「网络流 24 题」魔术球

这个可以化为最小路径覆盖问题。用上面的代码输出路径。

(要不是放在网络流里,这怎么可能想到嘛)

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=7e4+5;

struct P{
    int to,w,next;
}p[maxn<<2];
int head[maxn],cnt;

void add(int u,int v,int w)
{
    p[cnt].to=v;
    p[cnt].w=w;
    p[cnt].next=head[u];
    head[u]=cnt++;
}

int n;

int dep[maxn];

bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].w)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
        {
            p[i].w-=d;
            p[i^1].w+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }    
    }
    return w;
}

int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}


int son[maxn];
bool isson[maxn];
void getline()
{
    int u,v,f;
    for(u=1;u<=n;u++)
    {
        f=u;
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(p[i].w||i&1)continue;
            v=p[i].to;
            if(v>n)v-=n;
            son[f]=v;f=v;
            isson[v]=1;
            p[i].w=-1;
        }
    }
}

void addedge(int k)
{
    for(int i=1;i<=k;i++)
    {
        int up=i*i;
        for(int j=1;j<<1<=up;j++)
        {
            if(up-j>n)continue;
            if(j<<1==up)break;
            add(j,up-j+n,1);
            add(up-j+n,j,0);
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    int i,k,u,v,ed,res;
    scanf("%d",&k);
    n=(k+1)*(k+1)/2-1;
    ed=n*2+1;
    for(i=1;i<=n;i++)
    {
        add(0,i,1);add(i,0,0);
        add(i+n,ed,1);add(ed,i+n,0);
    }
    addedge(k);
    
    Dinic(0,ed);
    
    printf("%d
",n);
    getline();
    for(i=1;i<=n;i++)
    {
        if(isson[i])continue;
        u=i;
        printf("%d",u);
        while(son[u])
        {
            u=son[u];
            printf(" %d",u);
        }
        printf("
");
    }
}
View Code

 6004 「网络流 24 题」圆桌聚餐

满流的路径输出是那个流最后为零,那么它就与源点连通。

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=5e4+5;

struct P{
    int to,w,next;
}p[maxn<<2];
int head[maxn],cnt;

void add(int u,int v,int w)
{
    p[cnt].to=v;
    p[cnt].w=w;
    p[cnt].next=head[u];
    head[u]=cnt++;
}

int n;

int dep[455];

bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].w)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
        {
            p[i].w-=d;
            p[i^1].w+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }    
    }
    return w;
}

int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}


vector<int>allfa[455];
void getline(int a)
{
    int u,v;
    for(u=a;u<=n;u++)
    {
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            v=p[i].to;
            if(p[i].w!=0||i&1)continue;
            allfa[v].push_back(u);
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    int i,j,u,v,w,ed,res,sum=0;
    scanf("%d%d",&u,&v);
    n=u+v;
    ed=n+1;
    for(i=1;i<=u;i++)
    {
        scanf("%d",&w);
        sum+=w;
        add(i,ed,w);add(ed,i,0);
    }
    for(i=1;i<=v;i++)
    {
        scanf("%d",&w);
        add(0,u+i,w);add(u+i,0,0);
        for(j=1;j<=u;j++)
        {
            add(u+i,j,1);
            add(j,u+i,0);
        }
    }
    
    res=Dinic(0,ed);
    if(res!=sum)
    {
        printf("0
");return 0;
    }
    printf("1
");
    getline(u+1);
    for(i=1;i<=u;i++)
    {
        for(j=0;j<allfa[i].size();j++)printf("%d ",allfa[i][j]-u);
        putchar(10);
    }
}
View Code

 6005 「网络流 24 题」最长递增子序列

一件事:网络流可以在计算出当前最大流后,放松流(边)的限制再累加求扩充流量后的最大流。不影响正确性。

这道题依旧是割裂点。

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e6+50;

struct P{
    int to,w,next;
}p[maxn];
int head[1050],cnt,ed,a[1050],dp[1050];

void addline(int u,int v,int w)
{
    p[cnt].w=w;
    p[cnt].to=v;
    p[cnt].next=head[u];
    head[u]=cnt++;
}
void add(int u,int v,int w)
{
    addline(u,v,w);
    addline(v,u,0);
}


int dep[1050];
bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].w)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}

int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
        {
            p[i].w-=d;
            p[i^1].w+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}
int sum=0;
int Dinic(int st,int ed)
{
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}

int main()
{
    memset(head,-1,sizeof(head));
    int n,i,j,k,u,len=1;
    scanf("%d",&n);ed=2*n+1;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);dp[i]=1;add(i,i+n,1);
    }
    for(i=n-1;i>=1;i--)// dec
    {
        for(j=n;j>=i+1;j--)
        {
            if(a[i]>a[j])continue;
            dp[i]=max(dp[i],dp[j]+1);
            len=max(len,dp[i]);
        }
        for(j=n;j>=i+1;j--)
        {
            if(dp[i]==dp[j]+1&&a[i]<=a[j])add(n+i,j,1);
        }
    }
    printf("%d
",len);
//    for(i=1;i<=n;i++)printf("#%d# ",dp[i]);
    for(i=1;i<=n;i++)
    {
        if(dp[i]==len)add(0,i,1);
        if(dp[i]==1)add(n+i,ed,1);
    }
    printf("%d
",Dinic(0,ed));
    if(n==1)
    {
        printf("1
");
        return 0;
    }
    if(dp[1]==len)add(0,1,inf),add(1,n+1,inf);
    if(dp[n]==1)add(n,n*2,inf),add(n*2,ed,inf);
    printf("%d
",Dinic(0,ed));
    
}
View Code

6007 「网络流 24 题」方格取数

再说一次,一件事:最小割=最大流。

即使是放在网络流,即使告诉我是最小割,我也想不到该怎么做。

暴风哭泣。┭┮﹏┭┮

推荐洛谷题解,看一遍豁然开朗一遍,下一次又重新看一遍,豁然开朗一遍。(┬_┬)

题解说,二分图,然后源点连奇点,汇点连偶点,流量为点权,中间的点,互斥的点用inf流连接。题中同奇偶性必不互斥。

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e4+50;

struct P{
    int to,w,next;
}p[maxn<<3];
int head[maxn],cnt;

void addline(int u,int v,int w)
{
    p[cnt].w=w;
    p[cnt].to=v;
    p[cnt].next=head[u];
    head[u]=cnt++;
}
void add(int u,int v,int w)
{
    addline(u,v,w);
    addline(v,u,0);
}

int dep[maxn];


bool bfs(int st,int ed)
{
    memset(dep,-1,sizeof(dep));
    int u;
    queue<int>que;
    que.push(st);dep[st]=0;
    while(!que.empty())
    {
        u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            if(dep[p[i].to]==-1&&p[i].w)
            {
                dep[p[i].to]=dep[u]+1;
                if(p[i].to==ed)return 1;
                que.push(p[i].to);
            }
        }
    }
    return dep[ed]!=-1;
}
int dfs(int st,int ed,int lim)
{
    if(!lim||st==ed)return lim;
    int w=0,d;
    for(int i=head[st];i!=-1;i=p[i].next)
    {
        if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim))))
        {
            p[i].w-=d;
            p[i^1].w+=d;
            w+=d;
            lim-=d;
            if(!lim)break;
        }
    }
    return w;
}
int Dinic(int st,int ed)
{
    int sum=0;
    while(bfs(st,ed))sum+=dfs(st,ed,inf);
    return sum;
}

int main()
{
    memset(head,-1,sizeof(head));
    int n,m,st,ed,a,u,sum=0;
    scanf("%d%d",&n,&m);
    st=0;ed=n*m+1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a);
            sum+=a;
            u=(i-1)*m+j;
            if((i+j)%2)
            {
                add(st,u,a);
                if(j>1)add(u,u-1,inf);
                if(i>1)add(u,u-m,inf);
                if(j<m)add(u,u+1,inf);
                if(i<n)add(u,u+m,inf);
            }
            else add(u,ed,a);
        }
    }
    printf("%d
",sum-Dinic(st,ed));
}
View Code

原文地址:https://www.cnblogs.com/kkkek/p/11568623.html