网络流24题小结

题单总结
题单链接

dicnic模板

struct Dicnic {
    #define Type int
    int n, m, s, t;        //节点数,边数(包括反向弧),源点编号和汇点编号
    vector<Edge> edges;    //边表。edge[e]和edge[e^1]互为反向弧
    vector<int> G[N];   //邻接表,G[i][j]表示节点i的第j条边在e数组中的编号
    bool vis[N];        //BFS使用
    Type d[N];           //从起点到i的距离
    int cur[N];         //当前弧下标
    void init(int n) {
        this->n = n;
        for (int i = 0; i <= n; ++i) G[i].clear();
        edges.clear();
    }
    void addEdge(int from, int to, int cap) {
        edges.emplace_back(Edge(from, to, cap, 0));
        edges.emplace_back(Edge(to, from, 0, 0));
        m = int(edges.size());
        G[from].emplace_back(m-2);
        G[to].emplace_back(m-1);
    }
    bool BFS() {
        memset(vis, 0, sizeof(vis));
        memset(d, 0, sizeof(d));
        queue<int> q;
		while (!q.empty()) q.pop();
        q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            for (int i = 0; i < int(G[x].size()); ++i) {
                Edge &e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow) {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    Type DFS(int x, Type a) {
        if (x == t || a == 0) return a;
        Type flow = 0, f;
        for (int &i = cur[x]; i < int(G[x].size()); ++i) { //从上次考虑的弧
            Edge &e = edges[G[x][i]];
            if (d[x]+1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
                e.flow += f;
                edges[G[x][i]^1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }
    Type Maxflow(int s, int t) {
        this->s = s; this->t = t;
        Type flow = 0;
        while (BFS()) {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, INF);
        }
        return flow;
    }
    #undef Type
}dicnic;

spfa费用流模板

struct MCMF {
    int n, m;
    vector<Edge> edges;
    vector<int> G[N];
    int inq[N];  //是否在队列中
    int d[N];    //bellmanford
    int p[N];    //上一条弧
    int a[N];    //可改进量
    void init(int n) {
        this->n = n;
        for (int i = 0; i <= n; ++i) G[i].clear();
        edges.clear();
    }
    void addEdge(int from, int to, int cap, int cost) {
        edges.emplace_back(Edge(from, to, cap, 0, cost));
        edges.emplace_back(Edge(to, from, 0, 0, -cost));
        m = int(edges.size());
        G[from].emplace_back(m - 2);
        G[to].emplace_back(m - 1);
    }
    bool spfa(int s, int t, int &flow, ll &cost) {
        for (int i = 1; i <= n; ++i) d[i] = INF;
        memset(inq, 0, sizeof(inq));
        d[s] = 0;
        inq[s] = 1;
        p[s] = 0;
        a[s] = INF;
        queue<int> q;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            inq[u] = 0;
            for (int i = 0; i < int(G[u].size()); ++i) {
                Edge &e = edges[G[u][i]];
                if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if (!inq[e.to]) {
                        q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
		//if (d[t] > k) return false;    //如果费用大于k就退出
		//if (d[t] >= 0) return false;   //最小费用流
        if (d[t] == INF) return false;
        flow += a[t];
        cost += (ll)d[t] * (ll)a[t];
        for (int u = t; u != s; u = edges[p[u]].from) {
            edges[p[u]].flow += a[t];
            edges[p[u] ^ 1].flow -= a[t];
        }
        return true;
    }
    int MincostMaxflow(int s, int t, ll &cost) {
        int flow = 0;
        cost = 0;
        while (spfa(s, t, flow, cost));
        return flow;
    }
}mcmf;

飞行员配对方案问题

  • 飞行员配对方案问题
    问题模型: 二分图最大匹配
    转换模型: 最大流
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100;   //点数
int n,m,u[maxn],v[maxn];
vector<int> idx;
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
    cin>>n>>m;
    m=m-n;
    dicnic.init(n+m+10);
    for(int i=1; i<=n; ++i) dicnic.addEdge(0, i, 1);
    for(int i=n+1; i<=n+m; ++i) dicnic.addEdge(i, n+m+1, 1);
    int tot=0;
    while(true){
        cin>>u[tot]>>v[tot];
        if(u[tot]==-1 && v[tot]==-1) break;
        dicnic.addEdge(u[tot], v[tot], 1);
        idx.emplace_back(dicnic.m-2);
        tot++;
    }
    cout<<dicnic.Maxflow(0, n+m+1)<<'\n';
    for(int x:idx){
        if(dicnic.edges[x].flow==dicnic.edges[x].cap){
            cout<<dicnic.edges[x].from<<' '<<dicnic.edges[x].to<<'\n';
        }
    }
    return 0;
}

太空飞行计划问题

  • 太空飞行计划问题
    问题模型: 最大权闭合子图
    转换模型: 最小割
    最大权闭合子图是一个权值和最大的子图,这个子图中每个点的后继也都在子图里。而这正是这题所限定的,某个实验一定需要规定的器材。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,x;
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    scanf("%d%d", &m, &n);
    int S=0, T=m+n+1;
    dicnic.init(T+5);
    int sum=0;
    for(int i=1; i<=m; ++i){
        int x;
        scanf("%d", &x);
        sum+=x;
        dicnic.addEdge(S, i, x);
        while(getchar()==' '){
            scanf("%d", &x);
            dicnic.addEdge(i, x+m, INF);
        }
    }
    for(int i=1; i<=n; ++i){
        int x;
        scanf("%d", &x);
        dicnic.addEdge(i+m, T, x);
    }
    int mincut=dicnic.Maxflow(S, T);
    for(int i=1; i<=m; ++i) if(dicnic.d[i]) printf("%d ", i);
    puts("");
    for(int i=m+1; i<=m+n; ++i) if(dicnic.d[i]) printf("%d ", i-m);
    puts("");
    printf("%d\n", sum-mincut);
    return 0;
}

最小路径覆盖问题

  • 最小路径覆盖问题
    问题模型: 有向无环图最小路径覆盖
    转换模型: 点数 - 最大流
    最后输出路径挺有意思的,首先明确中间的流只要满流,就说明他们连接的两个点连线是最小路径覆盖里的一条路,先用并查集维护一下起点,然后对于每个起点O(n^2)输出路径。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,fa[maxn];
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int findRoot(int x){
    if(x==fa[x]) return x;
    else{
        fa[x]=findRoot(fa[x]);
        return fa[x];
     }
}
void uniRoot(int a, int b){
    int aa=findRoot(a);
    int bb=findRoot(b);
    if(aa!=bb){
        fa[bb]=aa;
    }
}
void output(int x){
    int now=x;
    while(true){
        cout<<now<<' ';
        bool flag=false;
        for(int idx:dicnic.G[now]){
            Edge temp=dicnic.edges[idx];
            if(temp.from>=1 && temp.from<=n && temp.to>=n+1 && temp.to<=2*n && temp.flow==temp.cap){
                flag=true;
                now=temp.to-n;
                break;
            }
        }
        if(!flag) {
            cout<<'\n';
            break;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
    cin>>n>>m;
    dicnic.init(2*n+10);
    int s=0,t=2*n+1;
    vector<int> temp;
    for(int i=0; i<m; ++i){
        int u,v;
        cin>>u>>v;
        dicnic.addEdge(u, v+n, 1);
        temp.emplace_back(dicnic.m-2);
    }
    for(int i=1; i<=n; ++i) dicnic.addEdge(s, i, 1);
    for(int i=n+1; i<=2*n; ++i) dicnic.addEdge(i, t, 1);
    int maxflow=dicnic.Maxflow(s,t);
    int ans=n-maxflow;
    for(int i=0; i<=1000; ++i) fa[i]=i;
    for(int x:temp){
        Edge now=dicnic.edges[x];
        if(now.flow==now.cap){
            uniRoot(now.from, now.to-n);
        }
    }
    for(int i=1; i<=n; ++i){
        if(findRoot(i)==i){
            output(i);
        }
    }
    cout<<ans<<'\n';
    return 0;
}

圆桌问题

  • 圆桌问题
    问题模型: 二分图多重匹配
    转换模型: 最大流
#include <bits/stdc++.h>
using namespace std;
const int N = 1000+100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,r[N],c[N];
vector<int> ans[N];
vector< pair<int, int> > idx[N];
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n>>m;
    dicnic.init(n+m+10);
    int S=0, T=n+m+1;
    int sum=0;
    for(int i=1; i<=n; ++i){
        cin>>r[i];
        sum+=r[i];
        dicnic.addEdge(S, i, r[i]);
    }
    for(int i=n+1; i<=n+m; ++i){
        cin>>c[i];
        dicnic.addEdge(i, T, c[i]);
    }
    for(int i=1; i<=n; ++i){
        for(int j=n+1; j<=n+m; ++j){
            dicnic.addEdge(i, j, 1);
            idx[i].emplace_back(make_pair(dicnic.m-2, j-n));
        }
    }
    int maxflow=dicnic.Maxflow(S, T);
    if(maxflow!=sum) cout<<0<<'\n';
    else{
        cout<<1<<'\n';
        for(int i=1; i<=n; ++i){
            for(pair<int, int> pii:idx[i]){
                Edge temp=dicnic.edges[pii.first];
                if(temp.flow==temp.cap){
                    ans[i].emplace_back(pii.second);
                }
            }
        }
        for(int i=1; i<=n; ++i){
            for(int x:ans[i]) cout<<x<<' ';
            cout<<'\n';
        }
    }
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

最长不下降子序列问题


问题模型: 最多不相交路径
转换模型: 最大流
第一次做到要特判 n=1情况的网络流题啊,233。

#include <bits/stdc++.h>
using namespace std;
const int N = 2100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,a[N],dp[N];
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n;
    if(n==1){
        cout<<1<<'\n';
        cout<<1<<'\n';
        cout<<1<<'\n';
        return 0;
    }
    for(int i=1; i<=n; ++i){
        cin>>a[i];
        dp[i]=1;
    }
    int maxx=1;
    for(int i=1; i<=n; ++i){
        for(int j=1; j<i; ++j){
            if(a[j]<=a[i]) dp[i]=max(dp[i], dp[j]+1);
        }
        maxx=max(maxx, dp[i]);
    }
    cout<<maxx<<'\n';
    dicnic.init(2*n+20);
    int s=0, t=2*n+1;
    for(int i=1; i<=n; ++i){
        if(dp[i]==1) dicnic.addEdge(s, i, 1);
        if(dp[i]==maxx) dicnic.addEdge(i+n, t, 1);
        dicnic.addEdge(i, i+n, 1);
        for(int j=1; j<i; ++j){
            if(a[j]<=a[i] && dp[i]==dp[j]+1){
                dicnic.addEdge(j+n, i, 1);
            }
        }
    }
    int maxflow=dicnic.Maxflow(s, t);
    cout<<maxflow<<'\n';
    dicnic.init(2*n+20);
    for(int i=1; i<=n; ++i){
        if(dp[i]==1){
            if(i==1) dicnic.addEdge(s, i, INF);
            else dicnic.addEdge(s, i, 1);
        }
        if(dp[i]==maxx) {
            if(i==n) dicnic.addEdge(i+n, t, INF);
            else dicnic.addEdge(i+n, t, 1);
        }
        if(i==1 || i==n) dicnic.addEdge(i, i+n, INF);
        else dicnic.addEdge(i, i+n, 1);
        for(int j=1; j<i; ++j){
            if(a[j]<=a[i] && dp[i]==dp[j]+1){
                dicnic.addEdge(j+n, i, 1);
            }
        }
    }
    maxflow=dicnic.Maxflow(s, t);
    cout<<maxflow<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

试题库问题


问题模型: 二分图多重匹配
转化模型: 最大流

#include <bits/stdc++.h>
using namespace std;
const int N = 1300;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,k,need[N];
vector<int> ans[N];
vector<int> rev;
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n>>k;
    int sum=0;
    int s=0, t=n+k+1;
    for(int i=1; i<=n; ++i){
        cin>>need[i];
        dicnic.addEdge(k+i, t, need[i]);
        sum+=need[i];
    }
    for(int i=1; i<=k; ++i){
        int num;
        cin>>num;
        for(int j=0; j<num; ++j){
            int x;
            cin>>x;
            dicnic.addEdge(i, k+x, 1);
            rev.emplace_back(dicnic.m-2); //还是先把最后要处理的边存起来好一点,防止出错
        }
    }
    for(int i=1; i<=k; ++i) dicnic.addEdge(s, i, 1);
    int maxflow=dicnic.Maxflow(s, t);
    for(int idx:rev){
        Edge now=dicnic.edges[idx];
        if(now.cap==now.flow){
            ans[now.to-k].emplace_back(now.from);
        }
    }
    if(maxflow!=sum) cout<<"No Solution!"<<'\n';
    for(int i=1; i<=n; ++i){
        cout<<i<<": ";
        for(int x:ans[i]) cout<<x<<' ';
        cout<<'\n';
    }
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

方格取数问题


问题模型: 二分图最大点权独立集
转化模型: 最小割

#include <bits/stdc++.h>
using namespace std;
const int MA=110;
const int N = 10100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int mat[MA][MA],idx[MA][MA],n,m,dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n>>m;
    int tot=0;
    int sum=0;
    for(int i=1; i<=n; ++i){
        for(int j=1; j<=m; ++j){
            cin>>mat[i][j];
            sum+=mat[i][j];
            idx[i][j]=++tot;
        }
    }
    int s=0, t=tot+1;
    for(int i=1; i<=n; ++i){
        for(int j=1; j<=m; ++j){
            if((i+j)%2==0) {
                dicnic.addEdge(s, idx[i][j], mat[i][j]);
                for(int k=0; k<4; ++k){
                    int ti=i+dir[k][0];
                    int tj=j+dir[k][1];
                    if(ti<1 || ti>n || tj<1 || tj>m) continue;
                    dicnic.addEdge(idx[i][j], idx[ti][tj], INF);
                }
            }
            else dicnic.addEdge(idx[i][j], t, mat[i][j]);
        }
    }
    cout<<(sum-dicnic.Maxflow(s, t))<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

负载平衡问题


题目模型: 最小代价供求
转化模型: 最小费用最大流

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200;      //点数
const int INF = 0x3f3f3f3f;
int n,a[N];
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int cc)
        : from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
int myabs(int x){
    if(x<0) x=-x;
    return x;
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n;
    int sum=0;
    for(int i=1; i<=n; ++i){
        cin>>a[i];
        sum+=a[i];
    }
    int s=0, t=n+1;
    int avg=sum/n;
    mcmf.init(n+5);
    for(int i=1; i<=n; ++i){
        if(a[i]>avg) mcmf.addEdge(s,i,a[i]-avg,0);
        else if(a[i]<avg) mcmf.addEdge(i,t,avg-a[i],0);
    }
    for(int i=1; i<=n; ++i){
        if(a[i]>avg){
            for(int j=1; j<=n; ++j){
                if(a[j]<avg){
                    int temp=min(myabs(j-i), n-myabs(j-i));
                    mcmf.addEdge(i, j, INF, temp);
                }
            }
        }
    }
    ll cost=0;
    ll maxflow=mcmf.MincostMaxflow(s,t,cost);
    cout<<cost<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

运输问题


问题模型: 网络费用流量
转化模型: 最小费用最大流

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 510;      //点数
const int INF = 0x3f3f3f3f;
int n,m,a[N],b[N],mat[N][N];
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int cc)
        : from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>m>>n;
    int s=0, t=n+m+1;
    mcmf.init(t+5);
    for(int i=1; i<=m; ++i){
        cin>>a[i];
        mcmf.addEdge(s,i,a[i],0);
    }
    for(int i=1; i<=n; ++i){
        cin>>b[i];
        mcmf.addEdge(i+m,t,b[i],0);
    }
    for(int i=1; i<=m; ++i){
        for(int j=1; j<=n; ++j){
            cin>>mat[i][j];
            mcmf.addEdge(i,m+j,INF,mat[i][j]);
        }
    }
    ll co=0;
    ll maxflow=mcmf.MincostMaxflow(s,t,co);
    cout<<co<<'\n';
    mcmf.init(t+5);
    for(int i=1; i<=m; ++i) mcmf.addEdge(s,i,a[i],0);
    for(int i=1; i<=n; ++i) mcmf.addEdge(i+m,t,b[i],0);
    for(int i=1; i<=m; ++i){
        for(int j=1; j<=n; ++j){
            mcmf.addEdge(i,m+j,INF,-mat[i][j]);
        }
    }
    co=0;
    maxflow=mcmf.MincostMaxflow(s,t,co);
    cout<<-co<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

骑士共存问题


问题模型: 二分图最大独立集
转化模型: 最小割

#include <bits/stdc++.h>
using namespace std;
const int N = 40000+100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,m,mat[210][210],dir[8][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    memset(mat,0,sizeof(mat));
    cin>>n>>m;
    for(int i=0; i<m; ++i){
        int a,b;
        cin>>a>>b;
        mat[a][b]=-1;
    }
    int tot=1;
    int cnt=0;
    for(int i=1; i<=n; ++i){
        for(int j=1; j<=n; ++j){
            if(mat[i][j]==-1) continue;
            mat[i][j]=tot++;
            ++cnt;
        }
    }
    int s=0, t=tot;
    dicnic.init(tot+10);
    for(int i=1; i<=n; ++i){
        for(int j=1; j<=n; ++j){
            if(mat[i][j]==-1) continue;
            if((i+j)%2==0){
                dicnic.addEdge(s,mat[i][j],1);
                for(int k=0; k<8; ++k){
                    int tx=i+dir[k][0];
                    int ty=j+dir[k][1];
                    if(tx<1 || tx>n || ty<1 || ty>n || mat[tx][ty]==-1) continue;
                    dicnic.addEdge(mat[i][j],mat[tx][ty],1);
                }
            } else{
                dicnic.addEdge(mat[i][j],t,INF);
            }
        }
    }
    int maxflow=dicnic.Maxflow(s,t);
    cout<<cnt-maxflow<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

航空路线问题


题目模型: 最长不相交路径
思路: 最大费用最大流 == 负费用边最小费用最大流

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1100;      //点数
const int INF = 0x3f3f3f3f;
int n,m,tot=0,vis[N];
string s[N];
map<string,int> idx;
vector<int> v1,v2;
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int cc)
        : from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
void dfs1(int now){
    for(int x:mcmf.G[now+n]){
        Edge e=mcmf.edges[x];
        if(e.to<=n && e.cap==e.flow && !vis[e.to]){
            vis[e.to]=1;
            v1.emplace_back(e.to);
            dfs1(e.to);
            break;  //一定要立刻break,想想为什么
        }
    }
}
void dfs2(int now){
    for(int x:mcmf.G[now+n]){
        Edge e=mcmf.edges[x];
        if(e.to<=n && e.cap==e.flow && !vis[e.to]){
            vis[e.to]=1;
            v2.emplace_back(e.to);
            dfs2(e.to);
            break;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n>>m;
    mcmf.init(2*n+10);
    for(int i=1; i<=n; ++i){
        cin>>s[i];
        idx[s[i]]=++tot;
    }
    int S=1,T=2*n;
    for(int i=1; i<=n; ++i){
        if(i==1 || i==n) mcmf.addEdge(i,i+n,2,-1);
        else mcmf.addEdge(i,i+n,1,-1);
    }
    bool sp=false;
    for(int i=0; i<m; ++i){
        string s1,s2;
        cin>>s1>>s2;
        if(idx[s1]>idx[s2]){
            swap(s1,s2);
        }
        if(idx[s1]==1 && idx[s2]==n) sp=true;
        mcmf.addEdge(idx[s1]+n,idx[s2],1,0);
    }
    ll co=0;
    ll maxflow=mcmf.MincostMaxflow(S,T,co);
    if(maxflow==2){
        cout<<-co-2<<'\n';
        memset(vis,0,sizeof(vis));
        dfs1(1);
        dfs2(1);
        reverse(v2.begin(),v2.end());
        cout<<s[1]<<'\n';
        for(int x:v1){
            cout<<s[x]<<'\n';
        }
        for(int x:v2){
            cout<<s[x]<<'\n';
        }
        cout<<s[1]<<'\n';
    } else if(maxflow==1 && sp){
        cout<<2<<'\n';
        cout<<s[1]<<'\n';
        cout<<s[n]<<'\n';
        cout<<s[1]<<'\n';
    }
    else{
        cout<<"No Solution!"<<'\n';
    }
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

餐巾纸计划问题


问题模型: 线性规划网络流优化(我也不知道这是个啥,别人这么总结的。。)
转化模型: 最小费用最大流

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5000+100;      //点数
const int INF = 0x3f3f3f3f;
int num,a[N],p,m,f,n,s;
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int cc)
        : from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
}mcmf;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
//1~num坏抹布
//num+1~2*num好抹布
    cin>>num;
    mcmf.init(2*num+10);
    for(int i=1; i<=num; ++i) cin>>a[i];
    int S=0,T=2*num+1;
    cin>>p>>m>>f>>n>>s;
    for(int i=1; i<=num; ++i){
        mcmf.addEdge(S,i,a[i],0);
        mcmf.addEdge(i+num,T,a[i],0);
        mcmf.addEdge(S,i+num,INF,p);
        if(i+1<=num) mcmf.addEdge(i,i+1,INF,0);
        if(i+m<=num) mcmf.addEdge(i,i+m+num,INF,f);
        if(i+n<=num) mcmf.addEdge(i,i+n+num,INF,s);
    }
    ll co=0;
    int maxflow=mcmf.MincostMaxflow(S,T,co);
    cout<<co<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

最长k可重区间问题


问题模型: 不相交路径最大权
转化模型: 最大费用最大流

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1100;      //点数
const int INF = 0x3f3f3f3f;
int n,k;
vector<int> b;
struct node{
    int l,r,len;
}nd[N];
struct Edge{

}mcmf;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    cin>>n>>k;
    mcmf.init(2*n+10);
    for(int i=0; i<n; ++i){
        cin>>nd[i].l>>nd[i].r;
        nd[i].len=nd[i].r-nd[i].l;
        b.emplace_back(nd[i].l);
        b.emplace_back(nd[i].r);
    }
    sort(b.begin(),b.end());
    b.resize(unique(b.begin(),b.end())-b.begin());
    int len=int(b.size());
    int S=0,T=len+1;
    mcmf.addEdge(S,1,k,0);
    mcmf.addEdge(len,T,INF,0);
    for(int i=1; i<=len-1; ++i) mcmf.addEdge(i,i+1,INF,0);
    for(int i=0; i<n; ++i){
        int tl=lower_bound(b.begin(),b.end(),nd[i].l)-b.begin()+1;
        int tr=lower_bound(b.begin(),b.end(),nd[i].r)-b.begin()+1;
        mcmf.addEdge(tl,tr,1,-nd[i].len);
    }
    ll co=0;
    int maxflow=mcmf.MincostMaxflow(S,T,co);
    cout<<-co<<'\n';
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

魔术球问题


问题模型: 有向无环图最小路径覆盖
转化模型: 最大流

const int N = 10100;   //点数
const int INF = 0x3f3f3f3f; //ll 0x8个3fLL
int n,vis[N];
struct Edge{
    int from, to, cap, flow;  //如果要开ll的话,这边也要开ll
    Edge(int u, int v, int c, int f)
        : from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
}dicnic;
signed main() {
    cin>>n;
    dicnic.init(1000);
    int sum=0,now=1; //now是柱子
    int S=0,T=10010;
    for(;;){
        dicnic.addEdge(S,now*2,1);
        dicnic.addEdge(now*2+1,T,1);
        for(int i=int(sqrt(now))+1; i*i<now*2; ++i) dicnic.addEdge((i*i-now)*2,now*2+1,1);
        int add=dicnic.Maxflow(S,T);
        sum+=add;
        if(now-sum>n){
            break;
        }
        ++now;
    }
    --now;
    cout<<now<<'\n';
    ms(vis,0);
    for(int i=1; i<=now; ++i){
        if(vis[i]) continue;
        vis[i]=1;
        cout<<i<<' ';
        int u=i;
        for(;;){
            bool exec=false;
            for(int idx:dicnic.G[u*2]){
                Edge e=dicnic.edges[idx];
                if(e.flow==e.cap && e.to!=0){ //注意不能是流向源点的边!
                    exec=true;
                    u=(e.to-1)/2;
                    vis[u]=1;
                    cout<<u<<' ';
                    break;
                }
            }
            if(!exec) break;
        }
        cout<<'\n';
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值