BZOJ 1391 [Ceoi2008]order
1391: [Ceoi2008]order
Description
有N个工作,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成。 现在给出这些参数,求最大利润
Input
第一行给出 N,M(1<=N<=1200,1<=M<=1200) 下面将有N块数据,每块数据第一行给出完成这个任务能赚到的钱(其在[1,5000])及有多少道工序 接下来若干行每行两个数,分别描述完成工序所需要的机器编号及租用它的费用(其在[1,20000]) 最后M行,每行给出购买机器的费用(其在[1,20000])
Output
最大利润
Sample Input
2 3
100 2
1 30
2 20
100 2
1 40
3 80
50
80
110
100 2
1 30
2 20
100 2
1 40
3 80
50
80
110
Sample Output
50
HINT
此题颇为有趣。一看便能知道是最大权闭合子图。但怎么区分租赁与购买呢?做了此题,再与BZOJ 1497 [NOI2006]最大获利比较,一下子我就明白了。
此题中,n个工作的获益先加在一起。源点S与n个工作连一条流量为获利的边,m台机器与汇点T连一条流量为购买费用的边,工作与机器之间连上相应的租赁费用。这样,跑一遍最大流(最小割),然后sum-maxflow即可。
为什么是对的?因为租赁可以理解为暂时的专属的,而购买就是永恒的普遍的。这在建图中体现的很明显。
而NOI那道题中,只不过没有租赁,所以工作与机器之间是inf。
很有意思啊!
1 /************************************************************** 2 Problem: 1391 3 User: Doggu 4 Language: C++ 5 Result: Accepted 6 Time:4252 ms 7 Memory:47844 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 template<class T>inline void readin(T &res) { 14 static char ch;T flag=1; 15 while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1; 16 res=ch-48;while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag; 17 } 18 19 const int N = 10000; 20 const int M = 3000000; 21 struct Edge {int v,upre,cap,flow;}g[M]; 22 int head[N], ne=-1; 23 inline void adde(int u,int v,int cap) { 24 g[++ne]=(Edge){v,head[u],cap,0};head[u]=ne; 25 g[++ne]=(Edge){u,head[v],0,0};head[v]=ne; 26 } 27 28 #include <queue> 29 std::queue<int> q; 30 int n, m, s, t, sum, d[N], cur[N]; 31 bool BFS() { 32 while(!q.empty()) q.pop(); 33 memset(d,0,sizeof(d)); 34 q.push(s);d[s]=1; 35 while(!q.empty()) { 36 int u=q.front();q.pop(); 37 for( int i = head[u]; i != -1; i = g[i].upre ) { 38 int v=g[i].v; 39 if(!d[v]&&g[i].cap>g[i].flow) q.push(v), d[v]=d[u]+1; 40 } 41 } 42 return d[t]; 43 } 44 int DFS(int u,int a) { 45 if(u==t||a==0) return a; 46 int flow=0, f; 47 for( int &i = cur[u]; i != -1; i = g[i].upre ) { 48 int v=g[i].v; 49 if(d[v]==d[u]+1&&(f=DFS(v,std::min(a,g[i].cap-g[i].flow)))>0) { 50 flow+=f;a-=f; 51 g[i].flow+=f;g[i^1].flow-=f; 52 if(a==0) break; 53 } 54 } 55 if(flow==0) d[u]=0; 56 return flow; 57 } 58 void maxflow() { 59 int flow=0; 60 while(BFS()) { 61 memcpy(cur,head,sizeof(head)); 62 flow+=DFS(s,0x3f3f3f3f); 63 } 64 printf("%d\n",sum-flow); 65 } 66 67 int main() { 68 memset(head,-1,sizeof(head)); 69 readin(n);readin(m);s=0;t=n+m+1; 70 for( int i = 1, w, a, b, c; i <= n; i++ ) { 71 readin(w);readin(b); 72 adde(s,i,w);sum+=w; 73 for( int j = 1; j <= b; j++ ) { 74 readin(a);readin(c); 75 adde(i,n+a,c); 76 } 77 } 78 for( int i = 1,c; i <= m; i++ ) { 79 readin(c); 80 adde(n+i,t,c); 81 } 82 maxflow(); 83 return 0; 84 } 85