hdu-5855 Less Time, More profit(最大权闭合子图)

题目链接:

Less Time, More profit

Time Limit: 2000/1000 MS (Java/Others)  

  Memory Limit: 65536/65536 K (Java/Others)



Problem 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  payiti(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
1L,ti1000000000
1payi,proi30000
 

 

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个工厂,m个商店,每个商店只有在要求的工厂都建好后才能获得利润,而建一个工厂需要花费和时间,现在问你能获得利润至少为l的最短时间是多少,在这个时间下的最大利润是多少;
 
思路:
 
当时就知道是一个网络流的题,但是就是不知道怎么建图,因为没学过最大权闭合子图;最大权闭合子图的应用就是一个事件必须在其需要的所有前提都满足的情况下发生;
最大权闭合子图的算法就是点权为正的和减去最大流,跑最大流的图是这样建的:原图中u→v,那就u→v的cap为inf,i点权为正cap[s][i]=w[i],否则cap[i][e]=-w[i];
枚举最小时间,把这个时间之前的图建好,再跑最大流,写的渣渣代码毛了800+ms;
 
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack>
#include <map>
 
using namespace std;
 
#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));
 
typedef  long long LL;
 
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + '0');
    putchar('\n');
}
 
const LL mod=1e9+7;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=1e5+10;
const int maxn=210;
const double eps=1e-12;

int n,m,l,num[maxn],a[maxn][maxn],v[maxn],p[maxn];
int cap[2*maxn][2*maxn],path[2*maxn],minflow[2*maxn],s,e;
queue<int>qu;
struct node
{
    int va,t,id;
}po[210];
int cmp(node x,node y)
{
    return x.t<y.t;
}
int bfs()
{
    mst(path,-1);
    qu.push(s);
    path[s]=0;minflow[s]=inf;
    while(!qu.empty())
    {
        int fr=qu.front();
        qu.pop();
        for(int i=1;i<=e;i++)
        {
            if(path[i]==-1&&cap[fr][i])
            {
                minflow[i]=min(minflow[fr],cap[fr][i]);
                path[i]=fr;
                qu.push(i);
            }
        }
    }
    if(path[e]==-1)return 0;
    return minflow[e];
}
int maxflow(int x)
{
    mst(cap,0);
    int sum=0;
    For(i,1,m)
    {
        if(po[a[i][num[i]]].t<=po[x].t)
        {
            sum+=v[i];
            cap[s][i]=v[i];
            For(j,1,num[i])cap[i][m+a[i][j]]=inf;
        }
    }
    for(int i=1;i<=x;i++)
    {
        cap[i+m][e]=po[i].va;
    }
    int ans=0;
    while(bfs())
    {
        int temp=minflow[e];
        int cur=e;
        while(cur!=s)
        {
            int fa=path[cur];
            cap[fa][cur]-=temp;
            cap[cur][fa]+=temp;
            cur=fa;
        }
        ans+=temp;
    }
    //cout<<sum<<" "<<ans<<" &&&&"<<endl;
    if(sum-ans>=l)
    {
        printf("%d %d\n",po[x].t,sum-ans);
        return 1;
    }
    return 0;
}

int solve()
{
    s=0;e=n+m+1;
    int flag=1;
    For(i,1,n)
    {
        if(i!=n&&po[i].t==po[i+1].t)continue;
        else 
        {
            if(maxflow(i)){flag=0;break;}
        }
    }
    if(flag)printf("impossible\n");
}

int main()
{
    int t,Case=0;
    read(t);
    while(t--)
    {
        printf("Case #%d: ",++Case);
        read(n);read(m);read(l);
        For(i,1,n)
        {
            read(po[i].va);read(po[i].t);
            po[i].id=i;
        }
        sort(po+1,po+n+1,cmp);
        For(i,1,n)p[po[i].id]=i;
        For(i,1,m)
        {
            read(v[i]);read(num[i]);
            For(j,1,num[i])
            {
                read(a[i][j]);
                a[i][j]=p[a[i][j]];
            }
            sort(a[i]+1,a[i]+num[i]+1);
        }
        solve();
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/zhangchengc919/p/5777786.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值