HDU 5855 Less Time, More profit 最大权闭合子图

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5855

Less Time, More profit


Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/65536 K (Java/Others)
问题描述

The city planners plan to build N plants in the city which has M shops.

Each shop needs products from some plants to make profit of proi units.

Building ith plant needs investment of payi units and it takes ti days.

Two or more plants can be built simultaneously, so that the time for building multiple plants is maximum of their periods(ti).

You should make a plan to make profit of at least L units in the shortest period.

输入

First line contains T, a number of test cases.

For each test case, there are three integers N, M, L described above.

And there are N lines and each line contains two integers payi, ti(1<= i <= N).

Last there are M lines and for each line, first integer is proi, and there is an integer k and next k integers are index of plants which can produce material to make profit for the shop.

1 <= T <= 30
1 <= N, M <= 200
1≤L,ti≤1000000000
1≤payi,proi≤30000

输出

For each test case, first line contains a line “Case #x: t p”, x is the number of the case, t is the shortest period and p is maximum profit in t hours. You should minimize t first and then maximize p.

If this plan is impossible, you should print “Case #x: impossible”

样例

sample input
2

1 1 2
1 5
3 1 1

1 1 3
1 5
3 1 1

sample output
Case #1: 5 2
Case #2: impossible

题意

有n个工厂,建每个工厂需要花费payi,并且要ti天才能建完。
有m个商店,每个商店能盈利proi,并且需要若干个指定的工厂给它提供原料(缺一不可)。
现在问如何在最短的时间内收益最大。

题解

最大权闭合子图的裸题。(百度文库里面的算法合集之最小割的论文里面有详细介绍最大权闭合子图)
我们二分时间t,然后问题转化成了对满足条件的工厂与商店之间的图求一个最大权闭合子图的问题。我们按照最大权闭合子图的建图方式连边就行了。
建图:
增设源点0,汇点n+m+1。
源点向每个能够满足条件的商店(如果商店的一个需求工厂在时间上不满足条件,那么这个商店就不满足条件,直接忽视它)连边,容量为商店的利润。
商店向需求工厂建边,容量为无穷大。
工厂向汇点建边,容量为工厂的花费。
然后跑最大流,判断在二分的时间下,是否能创造大于等于L的利润。

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
//#define lson (o<<1)
//#define rson ((o<<1)|1)
//#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)

typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=444;

struct Edge {
    int u,v,cap,flow;
    Edge(int u,int v,int c,int f):u(u),v(v),cap(c),flow(f) {}
};

struct Dinic {
    int n,m,s,t;
    vector<Edge> egs;
    vector<int> G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];

    void init(int n) {
        this->n=n;
        rep(i,0,n+1) G[i].clear();
        egs.clear();
        m=0;
    }

    void addEdge(int u,int v,int cap) {
        egs.pb(Edge(u,v,cap,0));
        egs.pb(Edge(v,u,0,0));
        m=egs.sz();
        G[u].pb(m-2);
        G[v].pb(m-1);
    }

    bool BFS() {
        clr(vis,0);
        queue<int> Q;
        Q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!Q.empty()) {
            int x=Q.front();
            Q.pop();
            rep(i,0,G[x].sz()) {
                Edge& e=egs[G[x][i]];
                if(!vis[e.v]&&e.cap>e.flow) {
                    vis[e.v]=1;
                    d[e.v]=d[x]+1;
                    Q.push(e.v);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x,int a) {
        if(x==t||a==0) return a;
        int flow=0,f;
        for(int& i=cur[x]; i<G[x].size(); i++) {
            Edge& e=egs[G[x][i]];
            if(d[x]+1==d[e.v]&&(f=DFS(e.v,min(a,e.cap-e.flow)))>0) {
                e.flow+=f;
                egs[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s,int t) {
        this->s=s;
        this->t=t;
        int flow=0;
        while(BFS()) {
            clr(cur,0);
            flow+=DFS(s,INF);
        }
        return flow;
    }
} dinic;

PII plants[maxn];
int pi[maxn],vis[maxn];
vector<int> G[maxn];

int n,m,L;

int isok(int mid) {
    dinic.init(n+m+2);
    clr(vis,0);
    for(int i=1; i<=m; i++) {
        rep(j,0,G[i].size()) {
            int v=G[i][j];
            if(plants[v].Y>mid) {
                vis[i]=1;
                break;
            }
        }
    }
    int sumv=0;
    for(int i=1; i<=m; i++) {
        if(vis[i]) continue;
        sumv+=pi[i];
        dinic.addEdge(0,i,pi[i]);
        rep(j,0,G[i].size()) {
            int v=G[i][j];
            dinic.addEdge(i,v+m,INF);
        }
    }
    rep(i,1,n+1) {
        if(plants[i].Y>mid) continue;
        dinic.addEdge(i+m,m+n+1,plants[i].X);
    }
    return sumv-dinic.Maxflow(0,n+m+1);
}

void init() {
    rep(i,0,maxn) G[i].clear();
}

int main() {
    int tc,kase=0;
    scanf("%d",&tc);
    while(tc--) {
        scanf("%d%d%d",&n,&m,&L);
        init();
        rep(i,1,n+1) {
            scanf("%d%d",&plants[i].X,&plants[i].Y);
        }
        rep(i,1,m+1) {
            scanf("%d",&pi[i]);
            int cnt;
            scanf("%d",&cnt);
            while(cnt--) {
                int x;
                scanf("%d",&x);
                G[i].push_back(x);
            }
        }
        printf("Case #%d: ",++kase);
        int l=0,r=1000000000;
        if(isok(r)<L) {
            puts("impossible");
            continue;
        }
        while(l+1<r) {
            int mid=l+(r-l)/2;
            if(isok(mid)>=L) r=mid;
            else l=mid;
        }
        printf("%d %d\n",r,isok(r));
    }
    return 0;
}

//end-----------------------------------------------------------------------
/*
5 3 50
1 1
2 2
3 3
4 4
5 5
100 2 1 4
1 0
1 0
*/

转载于:https://www.cnblogs.com/fenice/p/5778116.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值