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);
    }
}
發佈了68 篇原創文章 · 獲贊 23 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章