省选专练川渝友谊考试S10礼物gift

门边少女 WBQ 想要给她的男朋友买礼物。

礼物有 n 种,每种礼物有一个价格 ai ,如果 WBQ 买了礼物 i,那么她需要付出 ai 的代价。 同时,还有 m 对关系 (pi, qi, bi) ,表示 WBQ 的男朋友如果同时收到了礼物 pi 和礼物 qi ,那 么他的心情就会变好 bi 。

WBQ 的零花钱有限。设她最终购买礼物一共花费了 A,使 WBQ 的男朋友心情变好了 B, 请你最大化 B/A;

首先这看上去是一个01分数规划+网络流。

还记得profit吗?

于是我考试就这样写的。

20.。。。卡成暴力分,原因是这个题卡精度,然后我define double int 65 tle 35

这是为什么。这个时候,这道题实际就是非朴素建边了。

对于每个点,选择它需要付出的代价为 2gai − degi ,对于每条边,割断它需要付出的代价就是它本身的 bi ,直接建图跑最小割即可。

#include<bits/stdc++.h>
using namespace std;
#define in get_int()
namespace FastIO{
	const int L=1<<15;
	char buf[L],*S,*T;
	char getchar(){
		if(S==T){T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}
		return *S++;
	}
	char read_char(){char c=getchar();while(!(33<=c&&c<=126))c=getchar();return c;}
	void get_string(char *s){
		char c=getchar();
		while(!(33<=c&&c<=126))c=getchar();
		while( (33<=c&&c<=126))*s++=c,c=getchar();
		*s=0;
	}
	int get_int(){
		int res=0,bj=1;char c=getchar();
		while(!isdigit(c)){if(c=='-')bj=-1;c=getchar();}
		while(isdigit(c)){res=res*10+c-'0';c=getchar();}
		return res*bj;
	}
}using FastIO::get_int;using FastIO::get_string;using FastIO::read_char;
const int N=200010;
const int INF=2139062143;
int n,m,s,t;int sum;
int a[N];
struct hh{int x,y;int l;}nex[N<<4],b[N];
int fir[N],SIZE,cur[N];
void add(int x,int y,int l)
{
	nex[++SIZE]=(hh){fir[x],y,l};fir[x]=SIZE;
	nex[++SIZE]=(hh){fir[y],x,0};fir[y]=SIZE;
}
int d[N];int q[N],head,tail;
bool bfs()
{
	head=tail=0;
	fill(d,d+t+1,0);
	d[t]=1;q[++tail]=t;
	while(head<tail)
	{
		int x=q[++head];
		for(int i=fir[x];i;i=nex[i].x)
		{
			int to=nex[i].y;
			if(nex[i^1].l>0&&!d[to]) 
			{
				d[to]=d[x]+1;
				if(to==s) return 1;
				q[++tail]=to;
			}
		}
	}
	return 0;
}
int dfs(int x,int f)
{
	if(x==t) return f;
	int dat=0;
	for(int &i=cur[x];i;i=nex[i].x)
	{
		int to=nex[i].y;
		if(nex[i].l>0&&d[to]==d[x]-1)
		{
			int w=dfs(to,min(f-dat,nex[i].l));
			dat+=w,nex[i].l-=w,nex[i^1].l+=w;
			if(fabs(dat-f)<0.0001) return f;
		}
	}
	return dat;
}
int dinic()
{
	int ans=0;
	while(bfs())
	{
		copy(fir,fir+1+t,cur);
		ans+=dfs(s,INF);
	} 
	return ans;
}
void clear()
{
	SIZE=1;
	fill(fir,fir+t+1,0);
}
void build(int x)
{
	clear();
	for(int i=1;i<=n;++i) add(s,i,2*a[i]*x);
	for(int i=1;i<=m;++i)
	{
		int x=b[i].x,y=b[i].y;
		add(x,y,b[i].l);add(y,x,b[i].l);
		add(x,t,b[i].l);add(y,t,b[i].l);
	}
}

int main(){	
	n=in,m=in;s=0;t=n+1;
	for(int i=1;i<=n;++i)a[i]=in;
	for(int i=1;i<=m;++i)b[i].x=in,b[i].y=in,b[i].l=in,sum+=2*b[i].l;
	int l=0,r=700;
	while(l<r)
	{
		int mid=l+r>>1;
		build(mid+1);
		if(sum-dinic()>0) 
			l=mid+1;
		else r=mid;
	}
	printf("%d",l);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值