HDU5855 Less Time, More profit(最大权闭合子图)

题目

Source

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

Description

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.

Input

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

Output

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个商店,如果各个商店所需要k间工厂都建了,那么就得到proi的收益。现在希望收益大于等于l,问在建工厂所花时间最少的前提下,能获得的最大收益是多少。

 

二分时间,判定最大收益能否大于等于l;而求最大收益,这就是典型的最大权闭合子图的模型了,最小割求解即可。

 

代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 444
#define MAXM 444*888

struct Edge{
    int v,cap,flow,next;
}edge[MAXM];
int vs,vt,NE,NV;
int head[MAXN];

void addEdge(int u,int v,int cap){
    edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
    edge[NE].next=head[u]; head[u]=NE++;
    edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
    edge[NE].next=head[v]; head[v]=NE++;
}

int level[MAXN];
int gap[MAXN];
void bfs(){
    memset(level,-1,sizeof(level));
    memset(gap,0,sizeof(gap));
    level[vt]=0;
    gap[level[vt]]++;
    queue<int> que;
    que.push(vt);
    while(!que.empty()){
        int u=que.front(); que.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next){
            int v=edge[i].v;
            if(level[v]!=-1) continue;
            level[v]=level[u]+1;
            gap[level[v]]++;
            que.push(v);
        }
    }
}

int pre[MAXN];
int cur[MAXN];
int ISAP(){
    bfs();
    memset(pre,-1,sizeof(pre));
    memcpy(cur,head,sizeof(head));
    int u=pre[vs]=vs,flow=0,aug=INF;
    gap[0]=NV;
    while(level[vs]<NV){
        bool flag=false;
        for(int &i=cur[u]; i!=-1; i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
                flag=true;
                pre[v]=u;
                u=v;
                //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
                aug=min(aug,edge[i].cap-edge[i].flow);
                if(v==vt){
                    flow+=aug;
                    for(u=pre[v]; v!=vs; v=u,u=pre[u]){
                        edge[cur[u]].flow+=aug;
                        edge[cur[u]^1].flow-=aug;
                    }
                    //aug=-1;
                    aug=INF;
                }
                break;
            }
        }
        if(flag) continue;
        int minlevel=NV;
        for(int i=head[u]; i!=-1; i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
                minlevel=level[v];
                cur[u]=i;
            }
        }
        if(--gap[level[u]]==0) break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return flow;
}

int n,m,l;
int pay[222],time[222],pro[222];
vector<int> need[222];

int isok(int t){
    vs=0; vt=n+m+1; NV=vt+1; NE=0;
    memset(head,-1,sizeof(head));
    int totpro=0;
    for(int i=1; i<=n; ++i){
        if(time[i]<=t) addEdge(i+m,vt,pay[i]);
    }
    for(int i=1; i<=m; ++i){
        bool flag=1;
        for(int j=0; j<need[i].size(); ++j){
            if(time[need[i][j]]>t){
                flag=0;
                break;
            }
        }
        if(flag==0) continue;
        addEdge(vs,i,pro[i]);
        totpro+=pro[i];
        for(int j=0; j<need[i].size(); ++j){
            addEdge(i,need[i][j]+m,INF);
        }
    }
    int res=totpro-ISAP();
    if(res>=l) return res;
    return -1;
}

int main(){
    int t;
    scanf("%d",&t);
    for(int cse=1; cse<=t; ++cse){
        scanf("%d%d%d",&n,&m,&l);
        for(int i=1; i<=n; ++i){
            scanf("%d%d",&pay[i],&time[i]);
        }
        for(int i=1; i<=m; ++i) need[i].clear();
        for(int i=1; i<=m; ++i){
            int a,b;
            scanf("%d%d",&pro[i],&a);
            for(int j=0; j<a; ++j){
                scanf("%d",&b);
                need[i].push_back(b);
            }
        }
        int l=0,r=1000000001;
        while(l<r){
            int mid=l+r>>1;
            if(isok(mid)!=-1) r=mid;
            else l=mid+1;
        }
        printf("Case #%d: ",cse);
        if(l==1000000001){
            puts("impossible");
            continue;
        }
        printf("%d %d\n",l,isok(l));
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/WABoss/p/5777426.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值