• P4177 [CEOI2008]order


    P4177 [CEOI2008]order

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

    输入输出格式
    输入格式:
    第一行给出 N,M(1<=N<=1200,1<=M<=1200) 下面将有N组数据。

    每组数据第一行给出完成这个任务能赚到的钱(其在[1,5000])及有多少道工序

    接下来若干行每行两个数,分别描述完成工序所需要的机器编号及租用它的费用(其在[1,20000]) 最后M行,每行给出购买机器的费用(其在[1,20000])

    输出格式:
    最大利润


    若是没有租用一说,本题即为最大权闭合子图求最小割。

    当有租用的时候,我们仍按照最大权闭合子图构建模型,与之前不同的是,有关系的两点连边容边不再是INF而是租用费用

    我们仍可以用之前的解释:要么舍弃报酬(即正权点),要么买器材(负权点);租用怎么办呢?对于一个实验,我们有了除了之前两种方案的(即不做工作或购买机器)的第三种选择,租用,所以在求最小割的时候,我们要么割断源点到正权之间的边(不做这项工作),要么割断负权到汇点之间的边(买机器),要么割断中间的边(在一个工作中租用仪器),求得的最小割即为舍弃的最小利益

    所以最优答案即为 总利益 - 舍弃的最小利益

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    typedef long long ll;
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 1000019,INF = 1e9;
    int numw,numm;
    int head[maxn],nume = 1;
    struct Node{
        int v,dis,nxt;
        }E[maxn << 3];
    void add(int u,int v,int dis){
        E[++nume].nxt = head[u];
        E[nume].v = v;
        E[nume].dis = dis;
        head[u] = nume;
        }
    int maxflow,s,t;
    int d[maxn];
    bool bfs(){
    	queue<int>Q;
    	memset(d,0,sizeof(d));
    	d[s] = 1;
    	Q.push(s);
    	while(!Q.empty()){
    		int u = Q.front();Q.pop();
    		for(int i = head[u];i;i = E[i].nxt){
    			int v = E[i].v;
    			if(!d[v] && E[i].dis){
    				d[v] = d[u] + 1;
    				Q.push(v);
    				if(v == t)return 1;
    				}
    			}
    		}
    	return 0;
    	}
    int Dinic(int u,int flow){
    	if(u == t)return flow;
    	int rest = flow,k;
    	for(int i = head[u];i;i = E[i].nxt){
    		int v = E[i].v;
    		if(d[v] == d[u] + 1 && E[i].dis){
    			k = Dinic(v,min(rest,E[i].dis));
    			if(!k)d[v] = 0;
    			E[i].dis -= k;
    			E[i ^ 1].dis += k;
    			rest -= k;
    			}
    		if(!rest)break;
    		}
    	return flow - rest;
    	}
    int tot;
    int main(){
    	s = 0, t = 10026;
    	numw = RD();numm = RD();
    	for(int i = 1;i <= numw;i++){
    		int money = RD(), num = RD();
    		tot += money;
    		add(s, i << 1, money);add(i << 1, s, 0);
    		for(int j = 1;j <= num;j++){
    			int index = RD(), rent = RD();
    			add(i << 1, index << 1 | 1, rent);
    			add(index << 1 | 1, i << 1, 0);
    			}
    		}
    	for(int i = 1;i <= numm;i++){
    		int money = RD();
    		add(i << 1 | 1, t, money);
    		add(t, i << 1 | 1, 0);
    		}
    	int flow = 0;
    	while(bfs())while(flow = Dinic(s,INF))maxflow += flow;
    	printf("%d
    ",tot - maxflow);
    	return 0;
    	}
    
  • 相关阅读:
    如何较为方便的在GMap.Net中实现车辆运行轨迹
    WPF中在摄像头视频上叠加控件的解决方案
    Image Perimeters
    [DFS]排队(间隔排列)-C++
    稀疏图判定
    兔子问题(Rabbit problem)
    YCOJ过河卒C++
    洛谷P1076 寻宝
    P1993 小K的农场(差分约束)
    大Jump!
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9285939.html
Copyright © 2020-2023  润新知