zoukankan      html  css  js  c++  java
  • bzoj1497【NOI2006】最大获利

    1497: [NOI2006]最大获利

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 3437  Solved: 1674
    [Submit][Status][Discuss]

    Description

    新的技术正冲击着手机通讯市场。对于各大运营商来说,这既是机遇,更是挑战。

    THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜。须要做太多的准备工作。仅就站址选择一项。就须要完毕前期市场研究、站址勘測、最优化等项目。

    在前期市场调查和站址勘測之后,公司得到了一共N个能够作为通讯信号中转站的地址,而因为这些地址的地理位置差异,在不同的地方建造通讯中转站须要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站须要的成本为Pi(1≤i≤N)。另外公司调查得出了全部期望中的用户群。一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司能够获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司能够有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么怎样选择终于建立的中转站才干让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)

    Input

    输入文件里第一行有两个正整数N和M 。第二行中有N个整数描写叙述每个通讯中转站的建立成本。依次为P1, P2, …, PN 。

    下面M行。第(i + 2)行的三个数Ai, Bi和Ci描写叙述第i个用户群的信息。

    全部变量的含义能够參见题目描写叙述。

    Output

    你的程序仅仅要向输出文件输出一个整数。表示公司能够得到的最大净获利。

    Sample Input

    5 5
    1 2 3 4 5
    1 2 3
    2 3 4
    1 3 3
    1 4 2
    4 5 3

    Sample Output

    4

    HINT

    【例子说明】选择建立1、2、3号中转站,则须要投入成本6,获利为10,因此得到最大收益4。【评分方法】本题没有部分分,你的程序的输出仅仅有和我们的答案全然一致才干获得满分,否则不得分。【数据规模和约定】 80%的数据中:N≤200,M≤1 000。 100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。

    Source




    最小割的应用

    先定义s割为选。t割为不选。

    我们能够先将全部收益加起来,再减去最小代价,即为终于答案。

    从源点s到全部用户节点i连边(s,i,c[i]),表示假设用户i不能满足,就会付出c[i]的代价。

    从全部中转站节点i到汇点t连边(i,t,p[i]),表示假设要建立中转站i。就要付出p[i]的代价。

    然后考虑用户对中转站的要求,两个中转站中仅仅要有一个没有,这个用户就不能满足,即仅仅要有一个中转站属于t割,那该用户也属于t割。仅仅要连边(i,a[i],inf)和(i,b[i],inf),由于长度为inf的边是一定不会成为割的。这种方法非常巧妙。




    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #define F(i,j,n) for(int i=j;i<=n;i++)
    #define D(i,j,n) for(int i=j;i>=n;i--)
    #define ll long long
    #define pa pair<int,int>
    #define maxn 60000
    #define maxm 320000
    #define inf 1000000000
    using namespace std;
    struct edge_type
    {
    	int next,to,v;
    }e[maxm];
    int head[maxn],cur[maxn],dis[maxn];
    int n,m,s,t,cnt=1,ans=0,x,y,z;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    inline void add_edge(int x,int y,int v)
    {
    	e[++cnt]=(edge_type){head[x],y,v};head[x]=cnt;
    	e[++cnt]=(edge_type){head[y],x,0};head[y]=cnt;
    }
    inline bool bfs()
    {
    	queue<int>q;
    	memset(dis,-1,sizeof(dis));
    	dis[s]=0;q.push(s);
    	while(!q.empty())
    	{
    		int tmp=q.front();q.pop();
    		if (tmp==t) return true;
    		for(int i=head[tmp];i;i=e[i].next) if (e[i].v&&dis[e[i].to]==-1)
    		{
    			dis[e[i].to]=dis[tmp]+1;
    			q.push(e[i].to);
    		}
    	}
    	return false;
    }
    inline int dfs(int x,int f)
    {
    	int tmp,sum=0;
    	if (x==t) return f;
    	for(int &i=cur[x];i;i=e[i].next)
    	{
    		int y=e[i].to;
    		if (e[i].v&&dis[y]==dis[x]+1)
    		{
    			tmp=dfs(y,min(f-sum,e[i].v));
    			e[i].v-=tmp;e[i^1].v+=tmp;sum+=tmp;
    			if (sum==f) return sum;
    		}
    	}
    	if (!sum) dis[x]=-1;
    	return sum;
    }
    inline void dinic()
    {
    	while (bfs())
    	{
    		F(i,1,t) cur[i]=head[i];
    		ans-=dfs(s,inf);
    	}
    }
    int main()
    {
    	n=read();m=read();
    	s=n+m+1;t=s+1;
    	F(i,1,n)
    	{
    		z=read();
    		add_edge(i+m,t,z);
    	}
    	F(i,1,m)
    	{
    		x=read();y=read();z=read();
    		ans+=z;
    		add_edge(s,i,z);
    		add_edge(i,x+m,inf);
    		add_edge(i,y+m,inf);
    	}
    	dinic();
    	printf("%d
    ",ans);
    }
    


  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    ddd
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6979416.html
Copyright © 2011-2022 走看看