[ネットワークフローに関する24の質問]問題解決レポート:K.航空路の問題(最小コストと最大フロー)

ここに画像の説明を挿入
【問題分析】

最長の2つのばらばらのパスを見つけ、最大コストと最大フローを使用して解決します。

【モデリング方法】

i番目の都市を2つの頂点<ia>、<ib>に分割します。

1.各都市iについて、容量が1でコストが1の有向エッジを(<ia>、<ib>)に接続します。特に(<1.a>、<1.b>)と(<Na >、<Nb>)容量は2に設定されます。
2.都市iとj(j> i)の間にルートがある場合は、容量が1、コストが0の有向エッジを<ib>から<ja>に接続します。

ソース<1.a>からシンク<Nb>への最大コストと最大フローを見つけます。(<1.a>、<1.b>)がいっぱいでない場合、解決策はありません。それ以外の場合、最大コストと最大フロー2であるソリューションがあります。

【モデリング分析】

各ルートは西から東へです。この質問は、ルートグラフで1からNまでの2つのばらばらのパスを見つけて、パスの長さの合計が最大になるように変換できます。ネットワークフローモデルへの変換は、2つの最も長い拡張パスを見つけることです。各都市は1回しか訪問できないため、都市を2点に分割し、容量が1の辺を接続し、コストを1に設定する必要があります。2つのパスが検出されるため、開始点と終了点の内側のエッジ容量を2に設定する必要があります。次に、コストフロー値-2は2つのパスの長さの合計です。容量が2つの辺が2つあり、コストに1が追加されているため、2に減ったのはなぜですか。最大コストと最大フローを見つけた後、(<1.a>、<1.b>)がフルフローでない場合、2(おそらく1または0)のパスが足りないため、解決策はありません。

[問題の別の解決策]

古典的なマルチスレッドの動的プログラミング問題。

#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);
}

おすすめ

転載: blog.csdn.net/weixin_45697774/article/details/108555522