P3705 [SDOI2017]新生舞会(01分数规划+费用流)

P3705 [SDOI2017]新生舞会

见识到了大名鼎鼎的 01 01 01分数规划…

显 然 这 是 个 二 分 图 , 但 是 这 个 价 值 计 算 放 置 太 头 疼 了 . . . . 显然这是个二分图,但是这个价值计算放置太头疼了.... ,....

令 ∑ a i ∑ b i = m a x x 令\frac{\sum a_i}{\sum b_i}=maxx biai=maxx

稍微变化一下 m a x x ∗ ∑ b i = ∑ a i maxx*\sum b_i=\sum{a_i} maxxbi=ai

也就是 ∑ ( a i − m a x x ∗ b i ) = 0 \sum (a_i-maxx*b_i)=0 (aimaxxbi)=0

那 我 们 二 分 m a x x , 把 边 权 看 成 a i − m a x x ∗ b i 那我们二分maxx,把边权看成a_i-maxx*b_i maxx,aimaxxbi

求 一 个 最 大 费 用 最 大 流 , 随 着 m a x x 的 增 大 费 用 肯 定 会 变 小 ! ! 求一个最大费用最大流,随着maxx的增大费用肯定会变小!! ,maxx!!

所 以 二 分 m a x x , 若 此 时 费 用 仍 然 大 于 0 , 说 明 m a x x 可 以 继 续 增 大 . 所以二分maxx,若此时费用仍然大于0,说明maxx可以继续增大. maxx,0,maxx.

很神奇吧?不复杂,却能巧妙地解决问题呢

#include 
using namespace std;
#define int long long
const int maxn=2e5+10;
const double eps=1e-7;
const int inf=1e9;
int n,m,s,t;
double mincost;
int head[maxn<<1],cnt=1,incf[maxn],pre[maxn],vis[maxn];
int a[109][109],b[109][109];
struct edge{
	int to,nxt,flow;double w;//分别代表 
}d[maxn<<1];
void add(int u,int v,int flow,double w)//最大流量,单位费用
{
	d[++cnt]=(edge){v,head[u],flow,w},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0,-w},head[v]=cnt;
} 
double dis[maxn];
bool spfa()
{
	queueq;
	for(int i=0;i<=t;i++)	dis[i]=-inf;
	memset(vis,0,sizeof(vis));
	q.push(s);
	dis[s]=0,vis[s]=1;
	incf[s] = inf;//初始流量无限大
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		vis[u]=0;//出队
		for(int i=head[u];i;i=d[i].nxt)
		{
			if( !d[i].flow )	continue;//无流量了	
			int v=d[i].to;
			if( dis[v]=0 )	return true;
	return false;
}
signed main()
{
	cin >> n;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		cin >> a[i][j];
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		cin >> b[i][j];
	double l=0,r=1e6,mid,ans;
	while( (r-l)>=eps )
	{
		mid=(l+r)/2.0;
		if( isok(mid) )	l=mid,ans=mid;
		else	r=mid;
	}
	printf("%.6f",ans);
}

你可能感兴趣的:(网络流24题)