[ネットワークフロー24の質問] B.宇宙飛行計画の問題(最小重量に対する最小重量の閉じたグラフ、最小重量の計画の出力)

照合されたアルゴリズムテンプレートのコレクション:ACMテンプレート


B.宇宙飛行計画の問題(最大重量の閉じたグラフから最小カットまで、最小カット計画からの出力)[州/ NOI-]

P2762宇宙飛行計画の問題

ここに画像の説明を挿入

【問題分析】

最大重量の閉グラフ問題を最小カット問題に変換し、最大フローで解くことができます。

【モデリング方法】

各実験を2部グラフXのセットの頂点と見なし、各デバイスを2部グラフYのセットの頂点と見なして、ソースSとシンクTを追加します。
1. Sから各Xiに収入の容量を持つ有向エッジを接続します。
2.その時点でYiからTへの支出が容量である有向エッジを接続します。
3.実験iに機器jが必要な場合は、XiからYjまで無限の容量を持つ有向エッジを接続します。

すべての実験の収入が合計と同じであることを数え、ネットワークMaxflowの最大フローを見つけます。最大利益はTotal-Maxflowです。対応する解は、Sセット内のポイントを最小カットで割ったものです。つまり、ブロッキングフローが最後のオーグメンテーションで見つかったときにSからアクセスできる頂点です。

【モデリング分析】

Sセットをカットで分割してソリューションとして定義し、カットセットの容量の合計は(選択されていないAセットの頂点のウェイト+選択されたBセットの頂点のウェイト)であり、カットと表示されます。 。Aセットのすべての頂点の重みの合計はTotalとして記録され、Total-Cutは(選択したAセットの頂点の重み-選択したBセットの頂点の重み)であり、これが目標です。関数は、Aとして示されます。目的関数Aを最大化するには、Cutをできる限り小さくする必要があります。Totalは固定値であるため、目的関数Aが最大値に達すると、Cutが最小、つまり最小のカットになります。

この問題の一般的なモデルは、最大の重みを持つ閉じたグラフです。関連する議論については、「情報学コンテストにおける最小カットモデルの適用」の著者であるHu Botaoを参照してください。

【振り返りとまとめ】

打ち切られた実験装置は使用された実験装置であり、打ち切られた実験は行われていない実験であるため、打ち切られたものはすべて費用であり、推定総収益から最小コストを差し引くことで最大の利益を得ます。
ソースポイントからシンクポイントへのすべてのパスについて、この実験を行わないことを意味する実験を遮断するか、この機器を購入することを意味する実験機器を遮断してから、この機器を必要とするすべての実験(それに接続されている実験)を遮断しますできます。
実験と装置の境界は不可分なので、a(使用する実験装置)はA(実験する必要があります)の点に集中する必要があります;およびb(使用しない実験装置)およびA(する必要があります)実験間に接続はないので、Aを介してソースに接続することはできません(実験が行われます)。Bと同じセットにのみ属することができます(すべての実験は行われません)。
このようにしてエッジに値を割り当て、カットごとにすべての実験のボーナスを使用します(w A + w B w_A + w_BwA+wB)マイナスカット(w B + wa w_B + w_awB+wA)このスキームへの答えは(w A − wa w_A-w_awAwA )、最大の答えはカット値を最小化することです。

最終的な出力スキーム:
Dnincを使用して最大フローを見つけることの利点は、レイヤーの数がINFの場合、エッジの容量が明らかに0より大きいため、出力に便利であるということです。つまり、このエッジを通過するトラフィックがないため、エッジに明らかに接続されます。実験や設備は使用せず(使用すると側面の容量が0になるため)そのまま出力してください。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>

using namespace std;
typedef long long ll;
const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;

inline int read(int &x)
{
    
    
    char c;x = 0;
    while(c < '0' || c > '9')c = getchar();
    while(c >= '0' && c <= '9'){
    
    x = x * 10 + c - '0';c = getchar();}
    return c == '\r' || c == '\n' ? 0 : 1;
}

int n, m;
int head[N], ver[M], nex[M], tot;
int deep[N];
int cur[N], S, T;
ll maxflow, edge[M];

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

bool bfs()
{
    
    
    memset(deep, 0x3f, sizeof deep);
    queue<int>q;
    q.push(S), deep[S] = 0, cur[S] = head[S];
    while(q.size())
    {
    
    
        int x = q.front();
        q.pop();
        for(int i = head[x]; ~i; i = nex[i]){
    
    
            int y = ver[i], z = edge[i];
            if(z > 0 && deep[y] == INF){
    
    
                q.push(y);
                deep[y] = deep[x] + 1;
                if(y == T)return true;
            }
        }
    }
    return false;
}

ll dfs(int x, ll flow)
{
    
    
    if(x == T)return flow;
    ll ans = 0, i, k;
    for(i = cur[x]; ~i && flow; i = nex[i]){
    
    
        cur[x] = i;
        int y = ver[i];
        ll z = edge[i];
        if(edge[i] > 0 && (deep[y] == deep[x] + 1))
        {
    
    
            k = dfs(y, min(flow, z));
            if(!k)deep[y] = 0;//待定
            edge[i] -= k;
            edge[i ^ 1] += k;
            ans += k;
            flow -= k;
        }
    }
    if(!ans)deep[x] = INF;//流量不为零,说明不是最小割
    return ans;
}

void dinic()
{
    
    
    while(bfs()){
    
    
        for(int i = 1; i <= n + m + 1; ++ i)
            cur[i] = head[i];
        maxflow += dfs(S, INF);
    }

}

int main()
{
    
    
    memset(head, -1, sizeof head);
    scanf("%d%d", &n, &m);
    S = 0, T = n + m + 1;
    ll sum = 0;

    for(int i = 1; i <= n; ++ i){
    
    
        int x, ch;
        ch = read(x);
        sum += x;
        add(S, i, x);
        while(ch){
    
    
            ch = read(x);
            add(i, x + n, INF);
        }
    }
    for(int i = 1; i <= m; ++ i){
    
    
        int x;
        scanf("%d", &x);
        add(i + n, T, x);
    }
    dinic();

    ll ans = sum - maxflow;


    for(int i = 1; i <= n; ++ i)
        if(deep[i] != INF)printf("%d ", i);
    puts("");
    for(int i = 1; i <= m; ++ i)
        if(deep[n + i] != INF)printf("%d ", i);
    puts("");
    printf("%lld\n", ans);
    return 0;
}

おすすめ

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