网络流24题

网络流24题


说在前边

  1. 一直没有完整的刷过这套题,打算最近一点点刷掉
  2. 通过《最小割模型在信息学竞赛中的应用》及《浅析一类最小割问题》学习常规建图技巧

飞行员配对方案问题

二分图最大匹配

#include <bits/stdc++.h>
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int M = 100005;
const int N = 202;
using namespace std;
int m,n;
struct edge{int e,nxt,w;}E[M<<1];
int h[N],cc;
void add(int u,int v,int w) {
    E[cc].e=v;E[cc].w=w;E[cc].nxt=h[u];h[u]=cc;++cc;
    E[cc].e=u;E[cc].w=0;E[cc].nxt=h[v];h[v]=cc;++cc;
}
int d[N],q[M],st,ed;
int bfs() {
    int l=0,r=0;
    for(int i=1;i<=n+2;++i) d[i]=0;
    q[r]=st;++r;d[st]=1;
    while(l<r) {
        int u=q[l];++l;
        for(int i=h[u];~i;i=E[i].nxt) {
            int v=E[i].e;
            if(!d[v]&&E[i].w) {
                d[v]=d[u]+1;
                q[r]=v;++r;
                if(v==ed)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u,int fl) {
    if(u==ed)return fl;
    int s=fl,t;
    for(int i=h[u];~i;i=E[i].nxt) {
        int v=E[i].e;
        if(d[v]==d[u]+1&&E[i].w&&s) {
            t=dfs(v,min(E[i].w,s));
            s-=t;
            E[i].w-=t;E[i^1].w+=t;
            if(s==0)return fl;
        }
    }
    if(s==fl) d[u]=0;
    return fl-s;
}
int dinic() {
    int ans=0;
    while(bfs())ans+=dfs(st,inf);
    return ans;
}
int main() {
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n+2;++i) h[i]=-1;
    st=n+1;ed=n+2;
    int u,v;
    while(scanf("%d%d",&u,&v)!=EOF) {
        if(u==-1&&v==-1)break;
        add(u,v,1);
    }
    for(int i=1;i<=m;++i) add(st,i,1);
    for(int i=m+1;i<=n;++i) add(i,ed,1);
    printf("%d\n",dinic());
    int f=0;
    for(int i=1;i<=m;++i) {
        for(int j=h[i];~j;j=E[j].nxt) {
            if(E[j].w==0&&E[j].e<=n)printf("%d %d\n",i,E[j].e),f=1;
        }
    }
    if(!f) puts("No Solution!");
    return 0;
}

太空飞行计划问题

最大权闭合子图,正点权连源,负点权连汇,点权的绝对值作为边权。原本图中的边容量为无穷。割集将图的源汇分开,与源点相通的点就是最大权闭合子图的点集。

#include <bits/stdc++.h>
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int M = 100005;
const int N = 500;
using namespace std;
int m,n;
struct edge{int e,nxt,w;}E[M<<1];
int h[N],cc;
void add(int u,int v,int w) {
    E[cc].e=v;E[cc].w=w;E[cc].nxt=h[u];h[u]=cc;++cc;
    E[cc].e=u;E[cc].w=0;E[cc].nxt=h[v];h[v]=cc;++cc;
}
int d[N],q[M],st,ed;
int bfs() {
    int l=0,r=0;
    for(int i=1;i<=n+m+2;++i) d[i]=0;
    q[r]=st;++r;d[st]=1;
    while(l<r) {
        int u=q[l];++l;
        for(int i=h[u];~i;i=E[i].nxt) {
            int v=E[i].e;
            if(!d[v]&&E[i].w) {
                d[v]=d[u]+1;
                q[r]=v;++r;
                if(v==ed)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u,int fl) {
    if(u==ed)return fl;
    int s=fl,t;
    for(int i=h[u];~i;i=E[i].nxt) {
        int v=E[i].e;
        if(d[v]==d[u]+1&&E[i].w&&s) {
            t=dfs(v,min(E[i].w,s));
            s-=t;
            E[i].w-=t;E[i^1].w+=t;
            if(s==0)return fl;
        }
    }
    if(s==fl) d[u]=0;
    return fl-s;
}
int dinic() {
    int ans=0;
    while(bfs())ans+=dfs(st,inf);
    return ans;
}
vector<int> v,v1,v2;
int vis[N];
void dfs2(int u) {
    vis[u]=1;
    if(u>=1&&u<=m)v1.push_back(u);
    if(u>m&&u<=n+m) v2.push_back(u-m);
    for(int i=h[u];~i;i=E[i].nxt) {
        int v=E[i].e;
        if(!vis[v]&&E[i].w>0)dfs2(v);
    }
}
int a[N],b[N];
int main() {
    scanf(" %d %d ",&m,&n);
    memset(h,-1,sizeof(h));
    st=m+n+1;ed=st+1;
    int ans = 0;
    for(int i=1;i<=m;++i) {
        string s;v.clear();
        getline(cin,s);int c=0;
        while(1){
            int tmp = 0;
            while(s[c]>='0'&&s[c]<='9'&&c<s.size()) tmp=tmp*10+s[c]-'0',++c;
            v.push_back(tmp);
            if(c==s.size()) break;
            while(s[c]<'0'||s[c]>'9'&&c<s.size()) ++c;
        }
        add(st,i,v[0]);
        ans+=v[0];
        a[i]=v[0];
        for(int j=1;j<v.size();++j) {
            add(i,v[j]+m,inf);
        }
    }
    for(int i=1;i<=n;++i) {int x;
        scanf("%d",&x);b[i]=x;
        add(i+m,ed,x);
    }

    ans-=dinic();

    dfs2(st);
    int t=0;
    for(auto x: v1)printf("%d ",x),t+=a[x];puts("");
    for(auto x: v2)printf("%d ",x),t-=b[x];puts("");
    printf("%d\n",ans);
    return 0;
}

最小路径覆盖问题

DAG最小路径覆盖,拆点二分图最大匹配。分析见这里

#include <bits/stdc++.h>
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int M = 1000005;
const int N = 1500;
using namespace std;
int m,n;
struct edge{int e,nxt,w;}E[M<<1];
int h[N],cc;
void add(int u,int v,int w) {
    E[cc].e=v;E[cc].w=w;E[cc].nxt=h[u];h[u]=cc;++cc;
    E[cc].e=u;E[cc].w=0;E[cc].nxt=h[v];h[v]=cc;++cc;
}
int d[N],q[M],st,ed;
int bfs() {
    int l=0,r=0;
    for(int i=1;i<=n+n+2;++i) d[i]=0;
    q[r]=st;++r;d[st]=1;
    while(l<r) {
        int u=q[l];++l;
        for(int i=h[u];~i;i=E[i].nxt) {
            int v=E[i].e;
            if(!d[v]&&E[i].w) {
                d[v]=d[u]+1;
                q[r]=v;++r;
                if(v==ed)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u,int fl) {
    if(u==ed)return fl;
    int s=fl,t;
    for(int i=h[u];~i;i=E[i].nxt) {
        int v=E[i].e;
        if(d[v]==d[u]+1&&E[i].w&&s) {
            t=dfs(v,min(E[i].w,s));
            s-=t;
            E[i].w-=t;E[i^1].w+=t;
            if(s==0)return fl;
        }
    }
    if(s==fl) d[u]=0;
    return fl-s;
}
int dinic() {
    int ans=0;
    while(bfs())ans+=dfs(st,inf);
    return ans;
}
int vis[N],in[N];
vector<int> G[N];
void dfs2(int u) {
    vis[u]=1;
    printf("%d ",u);
    for(int i=h[u];~i;i=E[i].nxt) {
        int v=E[i].e;
        if(v>n&&v<=2*n&&!vis[v-n])--in[v-n];
    }
    for(int i=h[u];~i;i=E[i].nxt)if(!E[i].w){
        int v=E[i].e;
        if(v>n&&v<=2*n&&!vis[v-n])dfs2(v-n);
    }
}

int main() {
    scanf(" %d %d ",&n,&m);
    memset(h,-1,sizeof(h));
    st = 2*n+1; ed = st+1;
    for(int i=1;i<=n;++i) add(st,i,1);
    for(int i=1;i<=n;++i) add(i+n,ed,1);
    for(int i=1;i<=m;++i) {int x,y;
        scanf("%d%d",&x,&y);
        add(x,y+n,1);
        ++in[y];
    }
    int ans = n - dinic();

    for(int i=1;i<=n;++i)if(!in[i]&&!vis[i]) {
        dfs2(i);puts("");
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/9326985.html