[网络流24题]太空飞行计划问题 题解

考虑网络流建模。
一个飞行任务依赖于一些产品,所以可以将任务抽象为正权点,产品抽象为负权点,然后跑最大权闭合子图即可。
输出方案是一大难点。
考虑最大权闭合子图的基本模型:割掉\(S\)与正权点间的边表示不选它。所以在最后一次被封锁住的\(BFS\)中,所有没割掉的点(还有流量)一定会被\(BFS\)到,而后它的所有后继,由于连的都是\(INF\)边,所以肯定也会被\(BFS\)到。所以,最后一次\(BFS\)中有标号的点就是一组合法方案。
然后就做完了。

#include <bits/stdc++.h>
#define dbg(x) cerr << #x " = " << x << "\n"
#define INF 0x3f3f3f3f

typedef long long LL;
typedef long double ld;
typedef unsigned long long ULL;

using namespace std;

template < typename T > inline void inp(T& t) {
    char c = getchar(); T x = 1; t = 0; while(!isdigit(c)) {if(c == '-') x = -1; c = getchar();}
    while(isdigit(c)) t = t * 10 + c - '0' , c = getchar();t *= x;
}
template < typename T , typename... Args > inline void inp(T& t , Args&... args) {inp(t); inp(args...);}
template < typename T > inline void outp(T t) {
    if(t < 0) putchar('-') , t = -t; T y = 10 , len = 1;
    while(y <= t) y *= 10 , len++; while(len--) y /= 10 , putchar(t / y + 48) , t %= y;
}
template < typename T > inline T mul(T x , T y , T MOD) {x=x%MOD,y=y%MOD;return ((x*y-(T)(((ld)x*y+0.5)/MOD)*MOD)%MOD+MOD)%MOD;}

const int MAXN = 50000 + 10;
int d[MAXN] , p[MAXN] , s , t;
struct EdgeList {
    int to[MAXN] , nxt[MAXN] , w[MAXN] , flow[MAXN] , head[MAXN] , gg[MAXN] , cnt;
    EdgeList() { memset(head , -1 , sizeof(head)); cnt = 0; }
    void AddEdge(int u , int v , int we) {
        to[cnt] = v; w[cnt] = we; flow[cnt] = 0; nxt[cnt] = head[u]; head[u] = cnt++;
        to[cnt] = u; w[cnt] = 0; flow[cnt] = 0; nxt[cnt] = head[v]; head[v] = cnt++;
    }
}E; 
bool bfs() {
    queue < int > q;
    for(int i = s; i <= t; i++) E.gg[i] = E.head[i] , d[i] = 0;
    q.push(s); d[s] = 1;
    while(!q.empty()) {
        int u = q.front(); q.pop(); 
        for(int i = E.head[u]; i != -1; i = E.nxt[i]) {
            int v = E.to[i] , w = E.w[i] , flow = E.flow[i];
            if(w > flow && !d[v]) {
                d[v] = d[u] + 1; q.push(v);
                if(v == t) return 1;
            }
        }
    }
    return 0;
}

int dfs(int u ,  int cap) {
    if(u == t || !cap) return cap;
    int outcap = 0;
    for(int i = E.head[u]; i != -1 && outcap < cap; i = E.nxt[i]) {
        int v = E.to[i] , w = E.w[i] , flow = E.flow[i];
        if(w > flow && d[v] == d[u] + 1) {
            int tmpcap = dfs(v , min(cap - outcap , w - flow));
            outcap += tmpcap; E.flow[i] += tmpcap; E.flow[i^1] -= tmpcap;
            if(outcap == cap) break;
        }
    }
    return outcap;
}
int RunDinic() { int ans = 0; while(bfs()) ans += dfs(s , INF); return ans; }
int m , n , pos[MAXN];

int main() {
    inp(m , n); s = 0 , t = m + n + 1;
    int ans = 0;
    for(int i = 1; i <= m; i++) {
        string x; getline(cin , x); vector < int > v; v.clear(); 
        x = x + " ";
        int num = 0;
        for(int j = 0; j < x.size(); j++) {
            if(x[j] == ' ') v.push_back(num) , num = 0;
            else num = num * 10 + x[j] - '0'; 
        }
        for(int j = 1; j < v.size(); j++) E.AddEdge(i , m + v[j] , INF);
        pos[i] = E.cnt;
        E.AddEdge(s , i , v[0]); ans += v[0];
    }
    for(int i = 1; i <= n; i++)
        inp(p[i]) , pos[m + i] = E.cnt , E.AddEdge(m + i , t , p[i]);
    int x = ans - RunDinic();
    
    for(int i = 1; i <= m; i++) if(d[i]) printf("%d " , i);
    puts("");
    for(int i = m + 1; i <= m + n; i++) if(d[i]) printf("%d " , i - m);
    cout << "\n" << x << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiM-817/p/10340441.html