[lnsyoj2610/luoguP2762] 太空飞行计划问题

题意

n 种实验,m 种器材,第 i 种实验需要器材集合为 Ri,完成第 i 种实验可以获得 wi 元,使用第 i 种器材需要 ci 元,求最大利润。

sol

将实验作为左部点,器材作为右部点,根据依赖关系连边,左部连边奖金,右部连边成本。
记选择做的实验收益和为 A,选择不做的实验收益和为 B,选择的器材成本为 a,不选择的器材成本为 b,则最小割为 B+a,那么使用总收益-最小割即为 A+BBa=Aa

代码

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

using namespace std;

const int N = 105, M = 6005, INF = 0x3f3f3f3f;

int h[N], e[M], cap[M], ne[M], idx;
int d[N], cur[N];
int n, S, T;
int nn, m;
int exprc[N], expr[N][N], cost[N];
char s[205];
bool st[N];

void add(int a, int b, int c){
    e[idx] = b, cap[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    e[idx] = a, cap[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}

void build(){
    memset(h, -1, sizeof h);
    n = nn + m + 2;
    S = n - 1, T = n;
    for (int i = 1; i <= nn; i ++ ) add(S, i, exprc[i]);
    for (int i = 1; i <= m; i ++ ) add(nn + i, T, cost[i]);
    for (int i = 1; i <= nn; i ++ )
        for (int j = 1; j <= expr[i][0]; j ++ )
            add(i, nn + expr[i][j], INF);
}

void print() {
    for (int i = 1; i <= nn; i ++ ) if (~d[i]) {
        printf("%d ", i);
        for (int j = 1; j <= expr[i][0]; j ++ )
            st[expr[i][j]] = true;
    }
    puts("");
    for (int i = 1; i <= m; i ++ )
        if (st[i])
            printf("%d ", i);
    puts("");
}

bool bfs(){
    queue<int> q;
    memset(d, -1, sizeof d);
    d[S] = 0, q.push(S), cur[S] = h[S];
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        for (int i = h[t]; ~i; i = ne[i]){
            int j = e[i];
            if (d[j] == -1 && cap[i]) {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if (j == T) return true;;
                q.push(j);
            }
        }
    }
    return false;
}

int find(int u, int limit){
    if (u == T) return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i]){
        int j = e[i];
        cur[u] = i;
        if (d[j] == d[u] + 1 && cap[i]){
            int t = find(j, min(cap[i], limit - flow));
            if (!t) d[t] = -1;
            cap[i] -= t; cap[i ^ 1] += t; flow += t;
        }
    }
    return flow;
}

int dinic(){
    int r = 0, flow;
    while (bfs()) while (flow = find(S, INF)) r += flow;
    return r;
}

int main(){
    scanf("%d%d", &nn, &m);
    int sum = 0;
    for (int i = 1; i <= nn; i ++ ) {
        scanf("%d", &exprc[i]);
        sum += exprc[i];
        memset(s, 0, sizeof s);
        cin.getline(s, 200);
        int ulen = 0, t;
        while (sscanf(s + ulen, "%d", &t) == 1) {
            expr[i][ ++ expr[i][0]] = t;
            if (!t) ulen ++ ;
            else 
                while (t) t /= 10, ulen ++ ;
            ulen ++ ;
        }
    }
    for (int i = 1; i <= m; i ++ ) scanf("%d", &cost[i]);

    build();

    int t = dinic();

    print();
    printf("%d\n", sum - t);
}
posted @   是一只小蒟蒻呀  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示