HDU 5855 Less Time, More profit 【最大流-最大权闭合子图】

作为多校签到题的存在….
题意:
n个工厂,m个商店
每个工厂有建造时间 ti ,花费 payi
每个商店和k个工厂有关,如果这k个工厂都建造了,那么能获利 proi
问你求收益(∑pro−∑pay)≥L时,首先满足时间t最小,其次是收益p最大

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;

const int maxn = 5005;
const int maxm = 500005;
const int inf = 0x3fffffff;
const long long MAX = 0x3fffffff;

int pre[maxn], num[maxm*4], tol;
int pas[maxn], q[maxn*4], top, fin;

bool unuse[maxn];

set<int>all[maxn];

long long pay[maxn], day[maxn], val[maxn];


struct edge{
    int u, v; 
    long long cap; 
    edge(){}
    edge(int a, int b, long long c)
    { u = a, v = b, cap = c; }
}edg[maxm*4];


void add(int n, int m, long long w){
    edg[tol] = edge(n, m, w);
    num[tol] = pre[n],
     pre[n] = tol++;
    edg[tol] = edge(m, n, 0); 
    num[tol] = pre[m],
     pre[m] = tol++;
}


void Init(int n){
    tol = 0;
    memset(pre, -1, sizeof(pre));
    for(int i = 0; i <= n; ++i) 
    pay[i] = day[i] = val[i] = 0,
     all[i].clear();
}


long long solve_DFS(int st, int end, long long low){
    if( st == end ) return low;
    long long a = 0, res = 0;
    for(int i = pre[st]; i != -1; i = num[i]){
        int v = edg[i].v;
        if(edg[i].cap && pas[v] == pas[st] +1 ){
            a = solve_DFS(v, end, min(low-res, edg[i].cap) );
            edg[i].cap -= a;
            edg[i^1].cap += a;
            res += a;
            if(res == low) 
            return res;
        }
    }
    if(res == 0) 
    pas[st] = -1;
    return res;
}

bool solve_BFS(int st, int end){
    memset(pas, -1, sizeof(pas));
    top = fin = 0;
    pas[st] = 0; 
    q[fin++] = st;
    while( top < fin  ){
        int u = q[top++];
        if( u == end ) return 1;
        for(int k = pre[u]; k != -1; k = num[k]){
            int v = edg[k].v;
            if(unuse[v])
            continue;
            if( edg[k].cap && pas[v] == -1){
                pas[v] = pas[u] + 1;
                q[fin++] = v;
            }
        }
    }
    return 0;
}

long long Solve(int st, int end){
    long long res = 0, minflow;
    while( solve_BFS(st, end) ){
        while( minflow = solve_DFS(st, end, inf) ) 
        res += minflow;
    }
    return res;
}


int main(){
    int T, ca = 1;
    int st, end;
    scanf("%d", &T);
    while(T--){
        int n, m;
        long long Pro;
        scanf("%d%d%lld", &n, &m, &Pro);

        Init(n+m+10);

        st = 0, end = n+m+1;
        long long setnum = 0;
        for(int i = 1; i <= n; ++i){
            scanf("%lld %lld", pay+i, day+i);
            add(i+m, end, pay[i]);
        }
        for(int k, i = 1; i <= m; ++i){
            scanf("%lld%d", val+i, &k);
            add(st, i, val[i]);
            setnum += val[i];
            for(int x, j = 0; j < k; ++j){
                scanf("%d", &x);
                all[x].insert(i);
                add(i, x+m, inf);
            }
        }
        long long  left = 0, right = MAX, pro,ans = -1;
        while(left <= right){
            long long mid = (left+right) /2, sum = setnum;
            for(int i = 0; i < tol; i += 2) 
            edg[i].cap += edg[i^1].cap, edg[i^1].cap = 0;

            memset(unuse, 0, sizeof(unuse));

            for(int i = 1; i <= n; ++i){
                if(day[i] <= mid) 
                continue;
                for(set<int>::iterator it = all[i].begin(); it != all[i].end(); ++it){
                    if(!unuse[*it]) sum -= val[*it], unuse[*it] = 1;
                }
            }
            long long  temp = Solve(st, end);
            temp = sum-temp;
            if(temp >= Pro) 
            right = mid-1,
            pro = temp, 
            ans = mid;
            else left = mid+1;
        }
        printf("Case #%d: ", ca++);
        if(ans == -1)
        printf("impossible\n");
        else 
        printf("%lld %lld\n", ans, pro);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值