[24 questions on network flow] Problem solving report: K. Air route problem (minimum cost and maximum flow)

Insert picture description here
【problem analysis】

Find the longest two disjoint paths and use the maximum cost and maximum flow to solve.

【Modeling method】

Split the i-th city into two vertices <ia>, <ib>.

1. For each city i, connect (<ia>,<ib>) a directed edge with a capacity of 1 and a cost of 1, especially (<1.a>,<1.b>) and (<Na >,<Nb>) The capacity is set to 2.
2. If there is a route between cities i and j (j>i), connect a directed edge with a capacity of 1 and a cost of 0 from <ib> to <ja>.

Find the maximum cost and maximum flow from source <1.a> to sink <Nb>. If (<1.a>,<1.b>) is not full, then there is no solution. Otherwise, there is a solution, which is the maximum cost and maximum flow-2.

【Modeling analysis】

Each route is from west to east. This question can be transformed into finding two disjoint paths from 1 to N in the route graph so that the sum of the path lengths is the largest. Transforming into a network flow model is to find the two longest augmentation paths. Since each city can only be visited once, it is necessary to divide the city into two points, connect a side with a capacity of 1, and set the cost to 1. Because two paths are to be found, the edge capacity inside the starting point and the end point should be set to 2. Then the cost flow value -2 is the sum of the lengths of the two paths, why is it reduced by 2, because there are two sides with a capacity of 2 and the cost of 1 is added. After finding the maximum cost and maximum flow, if (<1.a>,<1.b>) is not a full flow, then we have found not enough paths for 2 (maybe 1 or 0), so there is no solution.

[Another solution to the problem]

The classic multi-threaded dynamic programming problem.

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int N = 500007, M = 500007, INF = 0x3f3f3f3f;

namespace dinic{
    
    
    const int N = 500007, M = 500007, INF = 0x3f3f3f3f;
    const ll LINF = 0x3f3f3f3f3f;
    int S, T, n;
    int head[N], nex[M], ver[M], tot, cur[N];
    ll dist[N], edge[M], cost[M], maxflow, mincost;
    bool vis[N];

    inline void add(int x, int y, ll z, ll c, bool o = 1){
    
    
        ver[tot] = y;
        edge[tot] = z;
        cost[tot] = c;
        nex[tot] = head[x];
        head[x] = tot ++ ;
        if(o)add(y, x, 0, -c, 0);
    }

    inline bool spfa(){
    
    
        for(int i = 1; i <= n; ++ i)dist[i] =LINF;
        memset(vis, 0, sizeof vis);
        queue<int>q;
        q.push(S);
        dist[S] = 0;
        vis[S] = 1;
        while(q.size()){
    
    
            int x = q.front();
            q.pop();
            vis[x] = 0;
            for(int  i = head[x]; ~i ;i = nex[i]){
    
    
                int y = ver[i];
                ll z = edge[i], c = cost[i];
                if(dist[y] > dist[x] + z && z){
    
    
                    dist[y] = dist[x] + z;
                    if(!vis[y])
                        q.push(y), vis[y] = 1;
                }
            }
        }
        return dist[T] != LINF;
    }
    ll dfs(int x, ll flow = LINF){
    
    
        if(x == T)return flow;
        ll ans = 0, k, i;
        vis[x] = 1;
        for(int i = cur[x]; ~i; i = nex[i]){
    
    
            int y = ver[i];
            ll z = edge[i], c = cost[i];
            if(z && dist[y] == dist[x] + c && vis[y]){
    
    
                k = dfs(y, min(z, flow));
                if(!k)dist[y] = LINF;
                edge[i] -= k;
                edge[i ^ 1] += k;
                ans += k, mincost += k * c, flow -= k;
            }
            vis[x] = 0;
            return ans;
        }
    }

    inline void main(){
    
    
        while(spfa()){
    
    
            for(int i = 1; i <= n; ++ i)
                cur[i] = head[i];
            ll now;
            while((now = dfs(S)))
                maxflow += now;
        }
    }
    inline void init(int _n, int _S, int _T){
    
    
        n = _n, S = _S, T = _T, tot = 0, maxflow = 0, mincost = 0;
        memset(head, -1, sizeof head);
    }
}
map<string, int>ip;
bool way[N];
string s[N], ch;
int n, m, S, T;
int x, y;

inline void dfs1(int x){
    
    
    way[x] = 1;
    cout <<s[x - n] << endl;
    for(int i = dinic::head[x]; ~i; i = dinic::nex[i]){
    
    
        int y = dinic::ver[i], z = dinic::edge[i];
        if(y <= n && z){
    
    
            dfs1(y + n);
            break;
        }
    }
}

inline void dfs2(int x){
    
    
    for(int i = dinic::head[x]; ~i; i = dinic::nex[i]){
    
    
        int y = dinic::ver[i], z = dinic::edge[i];
        if(y <= n && z && !way[y + n])
            dfs2(y + n);

    }
    cout << s[x - n] << endl;
}

int main(){
    
    
    scanf("%d%d", &n, &m);
    S = 1, T = n << 1;
    bool flag = 0;
    dinic::init(n + n + n, S, T);
    for(int i = 1; i <= n; ++ i)
        cin >> s[i], ip[s[i]] = i;
    //i ~ n 表示入点 n + 1 ~ 2 * n 表示出点
    for(int i = 2; i < n; ++ i)
        dinic::add(i, n + i, 1, 1);
        cout << "ok" << endl;
    dinic::add(1, n + 1, 2, 1), dinic::add(n, n + n, 2, 1);
    while(m -- ){
    
    
        cin >> ch, x = ip[ch];
        cin >> ch, y = ip[ch];
        if(x > y)swap(x, y);
        flag |= (x == 1 && y == n);
        dinic::add(x + n, y, 1, 0);
    }
    cout << "ok" << endl;
    dinic:main();
        cout << "ok" << endl;
    if(dinic::maxflow == 2)printf("%d", dinic::mincost - 2);
    else if(dinic::maxflow == 1 && flag){
    
    
        printf("2\n");
        cout << s[1] << endl << s[n] <<endl << s[1] << endl;
        return 0;
    }
    else return !printf("No Solution!\n");
    for(int i = 1;  i <= n + 2; ++ i)
        way[i + n] = 0;
    dfs1(1 + n), dfs2(1 + n);
}

Guess you like

Origin blog.csdn.net/weixin_45697774/article/details/108555522