zoukankan      html  css  js  c++  java
  • 【XSY2718】gift 分数规划 网络流

    题目描述

      有(n)个物品,买第(i)个物品要花费(a_i)元。还有(m)对关系:同时买(p_i,q_i)两个物品会获得(b_i)点收益。

      设收益为(B),花费为(A),求(lceilfrac{B}{A} ceil-1)

      (nleq 400,mleq 200000,1leq a_i,b_ileq 100)

    题解

      显然这是一个分数规划问题。

      二分答案(s),判断答案是否能大于(s)

    [egin{align} frac{B}{A}&>s\ B&>As\ B-As&>0 end{align} ]

      问题转化成买一个物品获得(-a_is)点收益,求收益是否能(>0)

      显然这个可以用最大权闭合子图来做,点数为(n+m+2),边数为(n+3m),肯定会TLE

      考虑另一种连边方法。

      对于每个点(i),连边((S,i,-a_is))

      对于每一对关系,列一个方程,解得:连边((p_i,q_i,frac{1}{2}b_i),(q_i,p_i,frac{1}{2}b_i),(p_i,T,frac{1}{2}b_i),(q_i,T,frac{1}{2}b_i))

      答案就是(sum_{i=1}^mb_i-maxflow)

      因为容量为分数不好处理,所以可以把全部数( imes 2)

      这样做的点数是(n+2),边数是(2n+m)

      写ISAP不用卡常美滋滋。

    代码

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef long long ll;
    int rd()
    {
    	int s=0,c;
    	while((c=getchar())<'0'||c>'9');
    	s=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    		s=s*10+c-'0';
    	return s;
    }
    int sum=0;
    namespace flow
    {
    	int c[10000010];
    	int v[10000010];
    	int t[10000010];
    	int h[4010];
    	int n;
    	void add(int x,int y,int a)
    	{
    		n++;
    		v[n]=y;
    		c[n]=a;
    		t[n]=h[x];
    		h[x]=n;
    	}
    	void init()
    	{
    		memset(h,0,sizeof h);
    		n=0;
    	}
    	int S,T;
    	int num;
    	int d[4010];
    	int e[4010];
    	int cur[4010];
    	int op(int x)
    	{
    		return ((x-1)^1)+1;
    	}
    	queue<int> q;
    	void bfs()
    	{
    		memset(d,-1,sizeof d);
    		memset(e,0,sizeof e);
    		d[T]=0;
    		q.push(T);
    		int x,i;
    		while(!q.empty())
    		{
    			x=q.front();
    			q.pop();
    			e[d[x]]++;
    			for(i=h[x];i;i=t[i])
    				if(c[op(i)]&&d[v[i]]==-1)
    				{
    					d[v[i]]=d[x]+1;
    					q.push(v[i]);
    				}
    		}
    	}
    	int dfs(int x,int flow)
    	{
    		if(x==T)
    			return flow;
    		int s=0,u;
    		for(int &i=cur[x];i;i=t[i])
    			if(d[v[i]]==d[x]-1&&c[i])
    			{
    				u=dfs(v[i],min(flow,c[i]));
    				s+=u;
    				flow-=u;
    				c[i]-=u;
    				c[op(i)]+=u;
    				if(!flow)
    					return s;
    			}
    		e[d[x]]--;
    		if(!e[d[x]])
    			d[S]=num;
    		e[++d[x]]++;
    		cur[x]=h[x];
    		return s;
    	}
    	int solve()
    	{
    		bfs();
    		memcpy(cur,h,sizeof h);
    		int ans=0;
    		while(ans<2*sum&&d[S]>=0&&d[S]<=num-1)
    			ans+=dfs(S,2*sum-ans);
    		return ans;
    	}
    }
    using flow::S;
    using flow::T;
    using flow::num;
    int n,m;
    int lx[2000010];
    int ly[2000010];
    int lz[2000010];
    int s[4010];
    int a[4010];
    void add(int x,int y,int z)
    {
    	flow::add(x,y,z);
    	flow::add(y,x,0);
    }
    void add2(int x,int y,int z)
    {
    	flow::add(x,y,z);
    	flow::add(y,x,z);
    }
    int check(int x)
    {
    	flow::init();
    	int i;
    	S=n+1;
    	num=T=n+2;
    	for(i=1;i<=n;i++)
    	{
    		add(S,i,int(min(0x7fffffffll,2ll*a[i]*x)));
    		add(i,T,s[i]);
    	}
    	for(i=1;i<=m;i++)
    		if(lx[i]!=ly[i])
    			add2(lx[i],ly[i],lz[i]);
    	return flow::solve()<2*sum;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    #endif
    //	scanf("%d%d",&n,&m);
    	n=rd();
    	m=rd();
    	int i;
    	for(i=1;i<=n;i++)
    //		scanf("%d",&a[i]);
    		a[i]=rd();
    	for(i=1;i<=m;i++)
    	{
    //		scanf("%d%d%d",&lx[i],&ly[i],&lz[i]);
    		lx[i]=rd();
    		ly[i]=rd();
    		lz[i]=rd();
    		s[lx[i]]+=lz[i];
    		s[ly[i]]+=lz[i];
    		sum+=lz[i];
    	}
    	int l=0,r=sum;
    	while(l<r)
    	{
    		int mid=(l+r+1)>>1;
    		if(check(mid))
    			l=mid;
    		else
    			r=mid-1;
    	}
    	printf("%d
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    bzoj-2748 2748: [HAOI2012]音量调节(dp)
    bzoj-2338 2338: [HNOI2011]数矩形(计算几何)
    bzoj-3444 3444: 最后的晚餐(组合数学)
    codeforces 709E E. Centroids(树形dp)
    codeforces 709D D. Recover the String(构造)
    codeforces 709C C. Letters Cyclic Shift(贪心)
    codeforces 709B B. Checkpoints(水题)
    codeforces 709A A. Juicer(水题)
    Repeat Number
    hdu 1003 Max Sum (动态规划)
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513516.html
Copyright © 2011-2022 走看看