题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5855
Less Time, More profit
问题描述
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
21 1 2
1 5
3 1 11 1 3
1 5
3 1 1sample 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
*/