Advanced network flow algorithm Detailed

Advanced network flow algorithm Detailed

Basics

Since before written summary, this chapter written in relatively simple

The maximum flow

Model is that there are many tubes, inf outflow stream from the source point, ask how much traffic Meeting Point

One obvious idea is greedy, but it is easy to give counterexamples.

And a similar problem to plant trees after (appropriately titled this? Or called tree planting), that question is it greedy to take a point of negating the weight and the next election will not vote for it points merge, so you can achieve estoppel effect

Then we establish the reverse side, after each outgoing traffic, plus corresponding to the reverse side of the flow, so we can guarantee the correctness of the greedy.

When the edge weight to ensure that no negative negative able to run a minimum flow loop

Minimum percentage

= Maximum flow, you need to license three conclusions are inverse proposition No, there is evidence before writing the blog, do not write here

In fact, remember on the line (

EK algorithm

Each time find a way can be augmented flow of traffic on and put the edge set by the source to the sinks minus the traffic flow away

DINIC algorithm

Multiple augmented, this algorithm is relatively common, although there are better algorithms, but the title will not card

Bfs is the first concrete realization of a layered, then dfs flow away all traffic can flow, this part needs to look at the code to achieve

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue> 
#define ll long long
using namespace std;
const int N=201,M=10001;
struct node{
    int v,next;ll w;
}edge[M*2];
int top=1,head[N],cur[N];
const ll inf=100909260817ll;
inline void add(int from,int to,int w){
    edge[++top].v=to;
    edge[top].next=head[from];
    head[from]=top;
    edge[top].w=w;
}
inline int read(){
    char ch=getchar();int x=0;int pos=1;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return pos?x:-x;
}
int n,m,s,t;
int dir=0,level[N];
queue<int>q;
inline int Min(ll a,ll b){
    return a>b?b:a;
}
inline int bfs(){
    memset(level,-1,sizeof(level));
    level[s]=0;q.push(s);
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=head[now];i;i=edge[i].next){
            int v=edge[i].v;
            if(level[v]==-1&&edge[i].w){
                level[v]=level[now]+1;
                q.push(v);
            }
        }
    }
    if(level[t]==-1) return 0;
    else return 1;
}
inline ll dfs(int now,ll flow){
    if(now==t) return flow;
    ll res=flow;
    for(int &i=cur[now];i;i=edge[i].next){
        int v=edge[i].v;
        if(edge[i].w&&level[v]==level[now]+1){
            ll k=dfs(v,Min(edge[i].w,res));
            res-=k;edge[i].w-=k;edge[i^1].w+=k;
        }
        if(!res) break;
    }
    return flow-res;
}
inline ll dinic(){
    ll ans=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    n=read();m=read();s=read();t=read();
    for(int i=1;i<=m;i++){
        int ui=read(),vi=read(),wi=read();
        add(ui,vi,wi);
        add(vi,ui,0); 
    }
    printf("%lld",dinic());
    return 0;
}

The complexity of the bipartite graph

\(m*min(n^\frac{2}{3},m^\frac{1}{2})\)

Minimum Cost Flow

At this time, the flow of each tube has a cost. At maximum flow case is certainly a priority right to take the small side, so at this time to change the order of access DINIC on the line. This is done to bfs replaced spfa (right may have negative side, can not be used dij), look at the code to achieve it

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<ctime>
#define ll long long
#include<cstdlib>
#include<queue>
using namespace std;
const int N = 401,M=15001;
struct node{
    int u,v,c,w,nex;
}edge[M<<1];
int head[N],top=1;
const int inf = 1926081700;
inline void add(int u,int v,int w,int c){
    edge[++top].v=v;edge[top].w=w;edge[top].c=c;edge[top].nex=head[u];head[u]=top; 
} 
inline int read(){
    int x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
int n,m,maxflow,mincost,dis[N],vis[N],cur[N];
namespace DINIC{
    int s,t;
    int SPFA(){
        queue<int>q; q.push(s);
        for(int i=1;i<=n;i++) dis[i]=inf;
        dis[s]=0;
        while(!q.empty()){
            int now=q.front();q.pop();
            vis[now]=0;
            for(int i=head[now];i;i=edge[i].nex){
                int v=edge[i].v;
                if(edge[i].w&&dis[now]+edge[i].c<dis[v]){
                    dis[v]=dis[now]+edge[i].c;
                    if(!vis[v]) q.push(v),vis[v]=1; 
                }
            } 
        }
        return dis[t]==inf?0:1;
    } 
    int dfs(int now,int flow){
        if(now==t||flow==0) return flow;
        int res=flow;vis[now]=1;
        for(int &i=cur[now];i;i=edge[i].nex){
            int v=edge[i].v;
            if(!vis[v]&&edge[i].w&&dis[v]==dis[now]+edge[i].c){
                int nw=dfs(v,min(res,edge[i].w));
                res-=nw,edge[i].w-=nw,edge[i^1].w+=nw,mincost+=edge[i].c*nw;if(!res) break;
            }
        }
        vis[now]=0;
        return flow-res;
    }
    void solve(){
        while(SPFA()){
            memcpy(cur,head,sizeof(head));
            maxflow+=dfs(s,inf);
        }
    }
};
using namespace DINIC;
int main(){
    n=read(),m=read();s=1;t=n;
    for(int i=1,u,v,c,w;i<=m;i++){
        u=read(),v=read(),w=read(),c=read();
        add(u,v,w,c);
        add(v,u,0,-c);
    } 
    solve();
    printf("%d %d",maxflow,mincost);
    return 0;
}

Advanced

2020qbxt provincial election class was talking about (because the level of consideration for other people in front of the main speaker

Passive exchange feasible flow

Algorithms ideas:

  1. Each edge first forced stream bounds the flow, which would be the weight assigned to each edge Save lower bound upper bound, and the recording of each dot effluent flowing more or poly (a memory array \ (totflow \) represents inflow minus the outflow of traffic flow, in which case the imbalance, the need to balance traffic

  2. New sources and sinks super \ (S, T \)

  3. \ (totflow_i <0 \) , multiple inflow proof, require the flow of other points, this time to \ (S \) to \ (I \) connected \ (- totflow \) edge

    Otherwise proven multi-flowing, require additional points to make it flow through artwork, this time to \ (i \) to \ (T \) Even \ (totflow \) side

    While recording the weight and the positive weight point \ (\ SUM) (weight point and this point was positive weights and weight = negative weight and, as above plus \ (W \) it will be subtracted \ (W \) )

  4. From \ (S \) to \ (T \) run \ (Dinic \) , if the maximum flow = sum you can fully compensate for the imbalance, there are feasible flow, flow compared with each edge

    Lower Bound Capacity + - + Flow = lower bound of reverse flow side

The active exchange bounds maximum flow

The same algorithm is thinking:

  1. To \ (S \) to \ (T \) connected capacity \ (\ INF \) side, the circulation flow configuration
  2. The use of passive sinks feasible flow technique to determine whether a solution, pay attention to new sources and sinks and sinks difference between the original source
  3. If solution, from the remaining amount on the network \ (S \) to \ (T \) run \ (Dinic \) , is the maximum flow answers

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
const int inf = 192608170;
using namespace std;
int read(){
    int x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
const int N = 441,M=50001;
struct node{
    int v,nex,w;
}edge[M];
int head[N],top=1;
int s,t,ns,nt,n,m,totflow[M];
void add(int u,int v,int w){
    edge[++top].w=w;edge[top].nex=head[u];edge[top].v=v;head[u]=top;
    edge[++top].w=0;edge[top].nex=head[v];edge[top].v=u;head[v]=top;
}
int level[N],cur[N];
int bfs(){
    queue<int>q;
    memset(level,-1,sizeof(level));
    q.push(s);level[s]=0;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=edge[i].nex){
            int v=edge[i].v;
            if(level[v]==-1&&edge[i].w){
                level[v]=level[now]+1;
                q.push(v);
            }
        } 
    } 
    return level[t]!=-1;
}
int dfs(int now,int flow){
    int res=flow;
    if(now==t||flow==0) return flow;
    for(int &i=cur[now];i;i=edge[i].nex){
        int v=edge[i].v;
        if(level[v]==level[now]+1&&edge[i].w){
            int nw=dfs(v,min(edge[i].w,res));
            res-=nw;edge[i].w-=nw;edge[i^1].w+=nw;
            if(!res) break;
        } 
    }
    return flow-res;
}
int dinic(int S,int T){
    s=S,t=T;
    int ans=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        ans+=dfs(s,inf);
    }
    return ans;
    
}
int las[N];
void del(int now){
    edge[now].w=0;
}
int main(){
    n=read(),m=read(),ns=read(),nt=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),low=read(),up=read();
        add(u,v,up-low);
        totflow[u]-=low;totflow[v]+=low;
    }
    int num=top;
    int S=n+1,T=n+2,sum=0;
    for(int i=1;i<=n;i++){
        if(totflow[i]<0) add(i,T,-totflow[i]);
        else{
            add(S,i,totflow[i]);
            sum+=totflow[i];
        }
        las[i]=top;
    }
    add(nt,ns,inf);
    int ans=0;
    if(dinic(S,T)!=sum){
        printf("please go home to sleep");return 0;
    }else{
        ans=edge[top].w;
        del(top);del(top-1);
        ans+=dinic(ns,nt);
        printf("%d",ans);
    }
    return 0;
}

The active sink bounds minimum flow

Similarly, on the basis of the feasible flow, we wish to minimize the total flow

Then subtracting the maximum flow into actionable from \ (t \) to \ (s \) flow, maximum flow can run

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define ll long long
const ll inf = 19260817000000ll;
using namespace std;
ll read(){
    ll x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
const ll N = 100031,M=400001;
struct node{
    ll v,nex,w;
}edge[M];
ll head[N],top=1;
ll s,t,ns,nt,n,m,totflow[M];
void add(ll u,ll v,ll w){
    edge[++top].w=w;edge[top].nex=head[u];edge[top].v=v;head[u]=top;
    edge[++top].w=0;edge[top].nex=head[v];edge[top].v=u;head[v]=top;
}
ll level[N],cur[N];
ll bfs(){
    queue<ll>q;
    memset(level,-1,sizeof(level));
    q.push(s);level[s]=0;
    while(!q.empty()){
        ll now=q.front();
        q.pop();
        for(ll i=head[now];i;i=edge[i].nex){
            ll v=edge[i].v;
            if(level[v]==-1&&edge[i].w){
                level[v]=level[now]+1;
                q.push(v);
            }
        } 
    } 
    return level[t]!=-1;
}
ll dfs(ll now,ll flow){
    ll res=flow;
    if(now==t||flow==0) return flow;
    for(ll &i=cur[now];i;i=edge[i].nex){
        ll v=edge[i].v;
        if(level[v]==level[now]+1&&edge[i].w){
            ll nw=dfs(v,min(edge[i].w,res));
            res-=nw;edge[i].w-=nw;edge[i^1].w+=nw;
            if(!res) break;
        } 
    }
    return flow-res;
}
ll dinic(ll S,ll T){
    s=S,t=T;
    ll ans=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        ans+=dfs(s,inf);
    }
    return ans;
    
}
ll las[N];
void del(ll now){
    edge[now].w=0;
}
int main(){
    n=read(),m=read(),ns=read(),nt=read();
    for(ll i=1;i<=m;i++){
        ll u=read(),v=read(),low=read(),up=read();
        add(u,v,up-low);
        totflow[u]-=low;totflow[v]+=low;
    }
    ll num=top;
    ll S=n+1,T=n+2,sum=0;
    for(ll i=1;i<=n;i++){
        if(totflow[i]<0) add(i,T,-totflow[i]);
        else{
            add(S,i,totflow[i]);
            sum+=totflow[i];
        }
        las[i]=top;
    }
    add(nt,ns,inf);
    ll ans=0;
    if(dinic(S,T)!=sum){
        printf("please go home to sleep");return 0;
    }else{
        ans=edge[top].w;
        del(top);del(top-1);
        ans-=dinic(nt,ns);
        printf("%lld",ans);
    }
    return 0;
}

Some build graphical models

Maximum Weight closed subgraph

Consider building a new network flow diagram, and add sources and sinks \ (S \) , \ (T \)

  • S from the right point to all the positive sides even, flow point right
  • T from the right to all points even negative side, the flow rate of the absolute value of the right point
  • All edges in the original image is also connected in the new image, the flow rate infinite
  • The answer is "original right of Chiang Kai-shek and" minus "minimal cut new map"

Why did you do this?

Consider what we have to lay down the decision, the right to choose a number of positive points might want to choose some of the negative right to the point, we have to choose the decision not vote for these points, this thing can be cut to the minimum processing

  1. Consider a bipartite graph, so that the left is positive right spot, the right is a negative right point, apparently even among each side of the cutting edge is not required
  2. Due to be subtracted, no cut is the right represents the selected point is the right, the right to cut the negative negative expressed is selected from the right point in the closure of FIG.
  3. Cut ensures \ (S \) and (T \) \ does not communicate, the election is the right of the point (not cut on the left) it must be cut negative weight to the right side, represents a group selected negative right point are connected, ensure It is a closed figure, or vice versa
  4. Decision: You can select point cut to the left, and said they did not choose this point as well as a negative right successor, otherwise we chose, with a minimum cut algorithm for optimal decision-making scheme

example

Humanities and science subcommittee

Too bare the

Sushi Restaurant

The cost of separate, set to a negative value

Deliciousness obtained positive value, like that of FIG built below (assuming \ (= 2 A_1, A_2 =. 3, A_3 = 2 \) ( \ (m * 1 * 1 \) is a kind of cost, x 1 should not be , when not drawing attention))

The right to run the largest closed subgraph on it

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read(){
    int x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
const int N = 6001,M=50001;
const int inf = 192608170;
int n,m,id[N],idc[N],a[N],d[201][201],wd[201][201],s,t,cnt=0,aed[N];
int head[N],cur[N],top=1;
struct node{
    int v,nex,w;
}edge[M*2];
inline void add(int u,int v,int w){
    edge[++top].v=v;edge[top].nex=head[u];edge[top].w=w;head[u]=top;
    edge[++top].v=u;edge[top].nex=head[v];edge[top].w=0;head[v]=top;
}
int vis[N];
inline int bfs(){
    memset(vis,-1,sizeof(vis));
    queue<int>q;
    q.push(s);vis[s]=0;
    while(!q.empty()){
        int now=q.front();q.pop();
        for(register int i=head[now];i;i=edge[i].nex){
            int v=edge[i].v;
            if(vis[v]==-1&&edge[i].w){
                vis[v]=vis[now]+1;
                q.push(v);
            }
        }
    }
    return vis[t]!=-1;
}
inline int dfs(int now,int flow){
    int res=flow;
    if(now==t||!flow) return flow;
    for(int &i=cur[now];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]==vis[now]+1&&edge[i].w){
            int nw=dfs(v,min(res,edge[i].w));
            edge[i].w-=nw;edge[i^1].w+=nw;res-=nw;
            if(!res) break;
        }
    }
    return flow-res;
} 
inline int dinic(){
    int res=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        res+=dfs(s,inf);
    }
    return res;
}
int main(){
    n=read(),m=read();
    int tot=0;
//  printf("%d %d\n",cnt,top);
    for(register int i=1;i<=n;++i){
        a[i]=read();
        if(!id[a[i]]) id[a[i]]=++cnt;
    }
    for(register int i=1;i<=n;++i) idc[i]=++cnt; 
//  printf("%d %d\n",cnt,top);
    for(register int i=1;i<=n;++i){
        for(register int j=1;j<=n-i+1;++j){
            wd[i][i+j-1]=read();d[i][i+j-1]=++cnt;
        }
    }
    s=++cnt;
    t=++cnt;
//  printf("%d %d\n",cnt,top);
    for(register int len=n;len>=1;--len){
        for(register int l=1;l<=n-len+1;++l){
            int r=l+len-1;
            if(l!=r){
                add(d[l][r],d[l+1][r],inf);
                add(d[l][r],d[l][r-1],inf);
            }else{
                add(d[l][r],idc[l],inf);
                add(idc[l],t,a[l]);
                add(d[l][r],id[a[l]],inf);
            }
            if(wd[l][r]>0) add(s,d[l][r],wd[l][r]),tot+=wd[l][r];
            else if(wd[l][r]<0) add(d[l][r],t,-wd[l][r]);
        }
    }
//  printf("%d %d\n",cnt,top);
    for(register int i=1;i<=n;++i){
        if(!aed[a[i]]){
            add(id[a[i]],t,m*a[i]*a[i]);
            aed[a[i]]=1;
        }
    }
//  printf("%d %d\n",cnt,top);
/*  for(int i=1;i<=cnt;i++){
        for(int j=head[i];j;j=edge[j].nex){
            int v=edge[j].v;
            if(edge[j].w){
                printf("%d %d %d\n",i,v,edge[j].w);
            }
        }
    }*/
//  printf("%d %d ed\n",cnt,top);
    printf("%d",tot-dinic());
    return 0;
}

War of the Worlds

Bipartite + dinic, Dinic used here to determine the feasibility, cost flow not want to go above

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
const double eps = 1e-4; 
#define ll unsigned long long
using namespace std;
const int N=201,M=10001;
struct node{
    int v,next;ll w;
}edge[M*2];
int top=1,head[N],cur[N];
const ll inf=1009092608170000ll;
inline void add(int from,int to,ll w){
    edge[++top].v=to;edge[top].next=head[from];head[from]=top;edge[top].w=w;
    edge[++top].v=from;edge[top].next=head[to];head[to]=top;edge[top].w=0;
}
inline int read(){
    char ch=getchar();int x=0;int pos=1;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return pos?x:-x;
}
int n,m,s,t;
int dir=0,level[N];
queue<int>q;
inline ll Min(ll a,ll b){
    return a>b?b:a;
}
inline int bfs(){
    memset(level,-1,sizeof(level));
    level[s]=0;q.push(s);
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=head[now];i;i=edge[i].next){
            int v=edge[i].v;
            if(level[v]==-1&&edge[i].w){
                level[v]=level[now]+1;
                q.push(v);
            }
        }
    }
    if(level[t]==-1) return 0;
    else return 1;
}
inline ll dfs(int now,ll flow){
    if(now==t) return flow;
    ll res=flow;
    for(int &i=cur[now];i;i=edge[i].next){
        int v=edge[i].v;
        if(edge[i].w&&level[v]==level[now]+1){
            ll k=dfs(v,Min(edge[i].w,res));
            res-=k;edge[i].w-=k;edge[i^1].w+=k;
        }
        if(!res) break;
    }
    return flow-res;
}
inline ll dinic(){
    ll ans=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        ans+=dfs(s,inf);
    }
    return ans;
}
ll a[N],b[N],tot;
int mp[N][N]; 
int check(double now){
    s=n+m+1,t=n+m+2;
    memset(head,0,sizeof(head));
    for(int i=1;i<=top;i++){
        edge[i].v=edge[i].next=edge[i].w=0;
    }
    top=1;
    for(int i=1;i<=n;i++){
        add(i+m,t,a[i]);
    }       
    for(int i=1;i<=m;i++){
        add(s,i,(ll)(now*b[i]));
        for(int j=1;j<=n;j++){
            if(mp[i][j]) add(i,j+m,inf);
        }   
    }
    if(dinic()==tot){
        return 1;
    }else return 0;
}           
int main(){ 
    n=read();m=read();  
    for(int i=1;i<=n;i++){
        a[i]=read();a[i]*=1000ll;tot+=a[i];
    }       
    for(int i=1;i<=m;i++){
        b[i]=read();b[i]*=1000ll;
    }
    double l=0,r=0;
    /*for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            
        }   
    }*/ 
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            mp[i][j]=read();
            if(mp[i][j]) r+=(double)(a[j]/b[i]);
        }   
    }       
    while(l<r-eps){
        double mid=(l+r)/2.0;
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%.6f\n",r);
    return 0;
}

Expand the solution to a problem with the way there are different Dian

poj1149

Changing the construction of the embodiment of FIG: Considering pig sty flow points are O (nm), the flow of people between the points considered is O (n) of

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read(){
    int x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
const int N = 1005,M=2000001;
const int inf = 192608170;
int n,m,s,t;
int head[N],cur[N],top=1;
struct node{
    int v,nex,w;
}edge[M*2];
inline void add(int u,int v,int w){
    edge[++top].v=v;edge[top].nex=head[u];edge[top].w=w;head[u]=top;
    edge[++top].v=u;edge[top].nex=head[v];edge[top].w=0;head[v]=top;
}
int vis[N];
inline int bfs(){
    memset(vis,-1,sizeof(vis));
    queue<int>q;
    q.push(s);vis[s]=0;
    while(!q.empty()){
        int now=q.front();q.pop();
        for(register int i=head[now];i;i=edge[i].nex){
            int v=edge[i].v;
            if(vis[v]==-1&&edge[i].w){
                vis[v]=vis[now]+1;
                q.push(v);
            }
        }
    }
    return vis[t]!=-1;
}
inline int dfs(int now,int flow){
    int res=flow;
    if(now==t||!flow) return flow;
    for(int &i=cur[now];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]==vis[now]+1&&edge[i].w){
            int nw=dfs(v,min(res,edge[i].w));
            edge[i].w-=nw;edge[i^1].w+=nw;res-=nw;
            if(!res) break;
        }
    }
    return flow-res;
} 
inline int dinic(){
    int res=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        res+=dfs(s,inf);
    }
    return res;
}
int cont[N*12],las[N*12];
int main(){
    m=read(),n=read();
    s=n+1,t=n+2;
    for(int i=1;i<=m;i++){
        cont[i]=read();
    }
    for(int i=1;i<=n;i++){
        int A=read();
        for(int j=1;j<=A;j++){
            int k=read();
            if(!las[k]){
                add(s,i,cont[k]);
                las[k]=i;
            }else{
                add(las[k],i,inf);
                las[k]=i;
            }
        }
        int B=read();
        add(i,t,B); 
    }
    printf("%d",dinic());
    return 0;
}

CQOI2009 dancing

Model limitations, restrictions and at some point, can be removed at some point there is no limit point, the capacity of the intermediate side point even split out of the number of edges is the upper bound limit

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read(){
    int x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
const int N = 305,M=2000001;
const int inf = 192608170;
int n,m,s,t,k,mp[N][N];
int head[N],cur[N],top=1;
struct node{
    int v,nex,w;
}edge[M*2];
inline void add(int u,int v,int w){
    edge[++top].v=v;edge[top].nex=head[u];edge[top].w=w;head[u]=top;
    edge[++top].v=u;edge[top].nex=head[v];edge[top].w=0;head[v]=top;
}
int vis[N];
inline int bfs(){
    memset(vis,-1,sizeof(vis));
    queue<int>q;
    q.push(s);vis[s]=0;
    while(!q.empty()){
        int now=q.front();q.pop();
        for(register int i=head[now];i;i=edge[i].nex){
            int v=edge[i].v;
            if(vis[v]==-1&&edge[i].w){
                vis[v]=vis[now]+1;
                q.push(v);
            }
        }
    }
    return vis[t]!=-1;
}
inline int dfs(int now,int flow){
    int res=flow;
    if(now==t||!flow) return flow;
    for(int &i=cur[now];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]==vis[now]+1&&edge[i].w){
            int nw=dfs(v,min(res,edge[i].w));
            edge[i].w-=nw;edge[i^1].w+=nw;res-=nw;
            if(!res) break;
        }
    }
    return flow-res;
} 
inline int dinic(){
    int res=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        res+=dfs(s,inf);
    }
    return res;
}
int check(int mid){
    memset(head,0,sizeof head);
    for(int i=1;i<=top;i++){
        edge[i].v=edge[i].nex=edge[i].w=0;
    }
    top=1;
    for(int i=1;i<=n;i++){
        add(s,i,mid);
        add(i+n*3,t,mid);
        add(i,i+n,k);
        add(i+n*2,i+n*3,k);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(mp[i][j]){
                add(i,j+n*3,1);
            }else{
                add(i+n,j+n*2,1);
            }
        }
    }
    if(dinic()==mid*n){
        return 1;
    }else return 0;
}
char S[N];
int main(){
    n=read(),k=read();s=n*4+1,t=n*4+2;
    for(int i=1;i<=n;i++){
        scanf("%s",S);
        for(int j=1;j<=n;j++){
            mp[i][j]=S[j-1]=='Y';
        }
    }
    int l=0,r=n+1;
    while(l<r-1){
        int mid=(l+r)>>1;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%d",l);
    return 0;
}

Guess you like

Origin www.cnblogs.com/lcyfrog/p/12288604.html