zoukankan      html  css  js  c++  java
  • 【bzoj1391】[Ceoi2008]order 网络流最小割

    原文地址:http://www.cnblogs.com/GXZlegend/p/6796937.html


    题目描述

    有N个工作,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成。 现在给出这些参数,求最大利润

    输入

    第一行给出 N,M(1<=N<=1200,1<=M<=1200) 下面将有N块数据,每块数据第一行给出完成这个任务能赚到的钱(其在[1,5000])及有多少道工序 接下来若干行每行两个数,分别描述完成工序所需要的机器编号及租用它的费用(其在[1,20000]) 最后M行,每行给出购买机器的费用(其在[1,20000])

    输出

    最大利润

    样例输入

    2 3
    100 2
    1 30
    2 20
    100 2
    1 40
    3 80
    50
    80
    110

    样例输出

    50


    题解

    最小割,类似最大权闭合图

    首先考虑如果不能租用机器的话,那么就是一个最大权闭合图的水题,S向工作连容量为利润的边,工作向机器连容量为inf的边,机器向T连容量为费用的边,答案为sum-mincut。

    那么加上了租用机器该怎么办呢?其实是类似的。

    最大权闭合图求法中边容量为inf,目的是防止割断该边。本题中想割断工作与机器之间的边,则边容量不为inf,而是租用机器的费用。

    这与最大权闭合图求法的证明差不多,自己画一下推导推导就行了。

    此题需要加弧优化。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    queue<int> q;
    int head[3000] , to[4000000] , val[4000000] , next[4000000] , cnt = 1 , cur[4000000] , s , t , dis[3000];
    void add(int x , int y , int z)
    {
    	to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    	to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
    }
    bool bfs()
    {
    	int x , i;
    	while(!q.empty()) q.pop();
    	memset(dis , 0 , sizeof(dis));
    	dis[s] = 1 , q.push(s);
    	while(!q.empty())
    	{
    		x = q.front() , q.pop();
    		for(i = head[x] ; i ; i = next[i])
    			if(val[i] && !dis[to[i]])
    				dis[to[i]] = dis[x] + 1 , q.push(to[i]);
    	}
    	return dis[t] > 0;
    }
    int dinic(int x , int low)
    {
    	if(x == t) return low;
    	int temp = low , i , k;
    	for(i = cur[x] ; i ; i = next[i])
    	{
    		if(val[i] && dis[to[i]] == dis[x] + 1)
    		{
    			k = dinic(to[i] , min(temp , val[i]));
    			if(!k) dis[to[i]] = 0;
    			val[i] -= k;
    			if(val[i]) cur[x] = i;
    			val[i ^ 1] += k;
    			if(!(temp -= k)) break;
    		}
    	}
    	return low - temp;
    }
    int main()
    {
    	int n , m , i , a , k , p , c , sum = 0;
    	scanf("%d%d" , &n , &m);
    	s = 0 , t = n + m + 1;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%d%d" , &a , &k) , add(s , i , a) , sum += a;
    		while(k -- ) scanf("%d%d" , &p , &c) , add(i , p + n , c);
    	}
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d" , &a) , add(i + n , t , a);
    	while(bfs())
    	{
    		for(i = s ; i <= t ; i ++ ) cur[i] = head[i];
    		sum -= dinic(s , 0x7fffffff);
    	}
    	printf("%d
    " , sum);
    	return 0;
    }

     

  • 相关阅读:
    java
    java
    java
    js
    java
    异常之异常处理
    面向对象之元类
    面向对象之内置方法
    面向对象之反射
    面向对象之类方法与静态方法
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6796937.html
Copyright © 2011-2022 走看看