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

传送门

一道最大权闭合子图的题目。直接建图跑dinic就行了,答案为正权点-最大流。

那剩下的问题就是如果知道哪些点被选进最大权闭合子图。

我们知道一个简单割对应了一个闭合子图,当这个简单割是最小割,即最大流,其与\(s\)相关的点即为闭合子图。

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 105
#define INF 2147483647

struct edge {
    int v,next,f;
}G[MAXN*MAXN<<1];

int head[MAXN],cur[MAXN];
int d[MAXN];

int S,T;
int N,M,tot = -1;
bool flag;
int maxflow = 0,sum = 0;

inline int read() {
    char ch = ' '; int num = 0;
    while((ch>'9'||ch<'0')&&ch!='\n') ch = getchar();
    if(ch=='\n') {
        flag = true;
        return -1;
    }
    while(ch>='0'&&ch<='9') {
        num = num*10 + ch - '0';
        ch = getchar();
    }
    if(ch=='\n') flag = true;
    return num;
}

inline void add(int u,int v,int cap) {
    G[++tot].v = v; G[tot].f = cap; G[tot].next = head[u]; head[u] = tot;
}

inline bool bfs() {
    
    std::queue <int> q;
    std::memset(d,0,sizeof(d));

    d[S] = 1;
    q.push(S);

    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(int i=head[u];i!=-1;i=G[i].next) {
            int v = G[i].v;
            if(d[v]||!G[i].f) continue;
            d[v] = d[u] + 1;
            q.push(v);
        }
    }

    return d[T];
}

int dinic(int u,int a) {

    if(u==T) return a;
    int temp,flow = 0;
    for(int& i=cur[u];i!=-1;i=G[i].next) {
        int v = G[i].v;
        if(d[v]!=d[u]+1||G[i].f<=0) continue;
        temp = dinic(v,std::min(a,G[i].f));
        a -= temp; flow += temp; 
        G[i].f -= temp; G[i^1].f += temp;
        if(a==0) return flow;
    }
    return flow;
}

int main() {
    
    M = read(); N = read();
    S = M + N + 1; T = S + 1;

    std::memset(head,-1,sizeof(head));

    int w,v;
    for(int i=1;i<=M;++i) {
        w = read(); add(S,i,w); add(i,S,0);
        flag = false; sum += w;
        while(!flag) {
            v = read(); add(i,v+M,INF); add(v+M,i,0);
        }
    }

    for(int i=1;i<=N;++i) {
        w = read();
        add(i+M,T,w); add(T,i+M,0);
    }

    while(bfs()) {
        for(int i=1;i<=M+N+2;++i) cur[i] = head[i];
        maxflow += dinic(S,INF);
    }

    for(int i=1;i<=M;++i) {
        if(d[i]>0) printf("%d ",i);
    }
    puts("");
    for(int i=M+1;i<=M+N;++i) {
        if(d[i]>0) printf("%d ",i-M);
    }
    puts("");
    printf("%d",sum - maxflow);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Neworld2002/p/10346961.html