P2762 太空飞行计划问题 (最小割)

题意:n个实验 每个实验可获利ai元 做每个实验需要几个仪器

   购买每个仪器有不同的花费 不同实验可能会用到同一个仪器 只用购买一次 求最大收益

题解:............................................

   先讲玄学建图吧

   从s向每个实验连权值为仪器收益的边

   从每个仪器向t连权值仪器花费的边

   实验与仪器之间连INF的边

   答案等于所有实验的收益 减去 (最大流=最小割)

   感性的理解一下.. 你已经获得了实验的收益了 如果当前存在一条s->t的路径 那么就表示你这个实验 还欠缺着某个仪器没买

   因为把仪器割掉的含义是买这个仪器 所以才会减去花费

   如果把实验割掉了 那么显然就是不做这个实验

   然后输出方案也学到一个trick 就是在最后一次bfs的时候 如果当前点跑不到 dis = INF 那么意味着到这个点的边权被减为0了 流满了 就是这个点被割掉了

   在这个题里被割掉了就意味着 选择做实验 买仪器

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;

int n, m, s, t, maxflow, cnt;
struct node {
    int to, nex, val;
}E[100005];
int head[105];
int cur[105];

void addedge(int x, int y, int va) {
    E[++cnt].to = y; E[cnt].nex = head[x]; head[x] = cnt; E[cnt].val = va;
    E[++cnt].to = x; E[cnt].nex = head[y]; head[y] = cnt; E[cnt].val = 0;
}

int dep[105];
int inque[105];
bool bfs() {
    for(int i = 1; i <= t; i++) dep[i] = INF, inque[i] = 0, cur[i] = head[i];
    queue<int> que;
    que.push(s);
    dep[s] = 0, inque[s] = 1;

    while(!que.empty()) {
        int u = que.front();
        que.pop();
        inque[u] = 0;

        for(int i = head[u]; i; i = E[i].nex) {
            int v = E[i].to;
            if(E[i].val && dep[v] > dep[u] + 1) {
                dep[v] = dep[u] + 1;
                if(!inque[v]) {
                    que.push(v);
                    inque[v] = 1;
                }
            }
        }
    }
    return dep[t] != INF;
}

int vis;
int dfs(int x, int flow) {
    if(x == t) {
        maxflow += flow;
        vis = 1;
        return flow;
    }

    int rflow = 0;
    int used = 0;
    for(int i = cur[x]; i; i = E[i].nex) {
        cur[x] = i;
        int v = E[i].to;
        if(E[i].val && dep[v] == dep[x] + 1) {
            if(rflow = dfs(v, min(flow - used, E[i].val))) {
                used += rflow;
                E[i].val -= rflow;
                E[i ^ 1].val += rflow;
                if(used == flow) break;
            }
        }
    }
    return used;
}

void dinic() {
    maxflow = 0;
    while(bfs()) {
        vis = 1;
        while(vis) {
            vis = 0;
            dfs(s, INF);
        }
    }
}

int p[55];
int c[55];
int ans[55];
int viss[55];
int ned[55][55];
char tools[10000];

int main() {
    int sum = 0;
    scanf("%d%d", &n, &m);
    s = n + m + 1;
    t = s + 1;
    cnt = 1;
    int ulen;

    for(int i = 1; i <= n; i++) {
        scanf("%d", &p[i]);
        sum += p[i];
        addedge(s, i, p[i]);

        memset(tools, 0, sizeof(tools));
        cin.getline(tools, 10000);
        ulen = 0;
        int num;
        while(sscanf(tools + ulen, "%d", &num) == 1) {
            ned[i][num] = 1;
            addedge(i, n + num, INF);

            if(num == 0) ulen++;
            else {
                while(num) {
                    num /= 10;
                    ulen++;
                }
            }
            ulen++;
        }

    }
    for(int i = 1; i <= m; i++) scanf("%d", &c[i]);
    for(int i = 1; i <= m; i++) addedge(n + i, t, c[i]);
    dinic();

    for(int i = 1; i <= m; i++) {
        for(int j = head[i + n]; j; j = E[j].nex) {
            int v = E[j].to;
            if(v == t) {
                if(E[j].val == 0) viss[i] = 1;
                break;
            }
        }
    }

    for(int i = 1; i <= n; i++) {
        if(dep[i] != INF) printf("%d ", i);
    }
    puts("");

    for(int i = 1; i <= m; i++) {
        if(dep[i + n] != INF) printf("%d ", i);
    }
    puts("");
    printf("%d
", sum - maxflow);
    return 0;
}
View Code

   

原文地址:https://www.cnblogs.com/lwqq3/p/11198522.html