zoukankan      html  css  js  c++  java
  • [NOI 2006] 最大获利

    题目传送-Luogu4174

    题意:

    要建(n)个站,建第i个站的花费(p_i)
    (m)个收益机会,当第(A_i)和第(B_i)个站都被建立时可以得到收益(C_i).
    问最大收益为多少。
    (nle5000,mle50000,0le C_i,p_ile100)

    题解:

    考虑刚开始你能获得全部收益,然后要丢掉一些亏钱的。。
    考虑网络流求最小割。
    对于所有i,建立(S ightarrow i)的边权为(p_i)的边.
    对于所有机会i,建立(A_i ightarrow i+n),(B_i ightarrow i+n)边权为INF,以及(i+n ightarrow T),边权为(C_i).
    那么就是最小割了

    过程:

    网络流日常打错:
    1.bfs忘加必须有流量的限制。。

    代码:

    const int N=510,M=250010;
    int n,m;
    int p[N];
    struct PEO {
    	int a,b,v;
    	inline void in() {
    		read(a); read(b); read(v);
    	}
    }a[M];
    namespace FLOW {
    	const int ALL=N+M,EDGE=(N+M*3)<<1;
    	int S,T;
    	int head[ALL],nxt[EDGE],to[EDGE],cap[EDGE],lst=1;
    	inline void adde(int x,int y,int c) {
    		nxt[++lst]=head[x]; to[lst]=y; cap[lst]=c; head[x]=lst;
    	}
    	inline void con(int x,int y,int c) {
    		adde(x,y,c); adde(y,x,0);
    	}
    	int stp[ALL];
    	inline bool bfs(int S) {
    		queue<int> que; mem(stp,63);
    		que.push(S); stp[S]=0; 
    		while(!que.empty()) {
    			int u=que.front(); que.pop();
    			for(int i=head[u];i;i=nxt[i]) {
    				int v=to[i];
    				if(cap[i] && stp[v]>stp[u]+1) {
    					stp[v]=stp[u]+1;
    					que.push(v);
    				}
    			}
    		}
    		return stp[T]!=stp[0];
    	}
    	int cur[ALL];
    	inline int dfs(int u,int f) {
    		if(!f || u==T) return f;
    		for(int &i=cur[u];i;i=nxt[i]) {
    			int v=to[i];
    			if(stp[v]==stp[u]+1 && cap[i]) {
    				int flow=dfs(v,min(f,cap[i]));
    				if(flow) {
    					cap[i]-=flow; cap[i^1]+=flow;
    					return flow;
    				}
    			}
    		}
    		return 0;
    	}
    	inline int Dinic() {
    		int Flow=0,add=0;
    		while(bfs(S)) {
    
    			memcpy(cur,head,sizeof(head));
    			do {add=dfs(S,INF); Flow+=add;} while(add);
    		}
    		return Flow;
    	}
    	inline void Construct() {
    		S=n+m+1; T=S+1;
    		for(int i=1;i<=n;i++) {
    			con(S,i,p[i]);
    		}
    		for(int i=1;i<=m;i++) {
    			con(a[i].a,i+n,INF);
    			con(a[i].b,i+n,INF);
    			con(i+n,T,a[i].v);
    		}
    	}
    	inline int main() {
    		Construct();
    		// printf("%lld %lld %lld %lld
    ",S,T,lst,EDGE);
    		return Dinic();
    	}
    }
    int sum=0;
    signed main() {
    	read(n); m=n*n;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++) {
    			int p=(i-1)*n+j;
    			a[p].a=i; a[p].b=j; read(a[p].v);
    			sum+=a[p].v;
    		}
    	for(int i=1;i<=n;i++) read(p[i]);
    	int ans=FLOW::main();
    	printf("%d
    ",sum-ans);
    	return 0;
    }
    

    用时:25min

  • 相关阅读:
    描述一下Spring Bean的生命周期
    BeanFactory和ApplicationContext有什么区别
    谈谈你对AOP的理解
    谈谈对IOC的理解
    线程池中线程复用原理
    线程池中阻塞队列的最用?为什么是先添加队列而不是先创建最大线程
    为什么使用线程池?解释下线程池参数
    去噪声论文阅读
    怎么使用有三AI完成系统性学习
    JavaCnn项目注解
  • 原文地址:https://www.cnblogs.com/functionendless/p/9556661.html
Copyright © 2011-2022 走看看