洛谷P3705 [SDOI2017]新生舞会
思路:
∵
C
=
∑
a
∑
b
\because C=\cfrac{\sum a}{\sum b}
∵C=∑b∑a
∴
∑
a
−
C
∑
b
=
0
\therefore \sum a-C\sum b=0
∴∑a−C∑b=0
二分,令
w
=
a
−
m
i
d
×
b
w=a-mid\times b
w=a−mid×b,如果
m
i
d
>
c
mid>c
mid>c,那么
∑
w
<
0
\sum w<0
∑w<0,否则
∑
w
>
0
\sum w>0
∑w>0。
现在就转化为是权值为
a
−
m
i
d
×
b
a-mid\times b
a−mid×b的情况下,取
n
n
n个数,使每行每列能且只能取一次。这个就成了二分图带权匹配。
建图:
i
i
i表示行的点,
j
j
j表示列的点。
1、
S
S
S向
i
i
i建
(
S
,
i
,
1
,
0
)
(S,i,1,0)
(S,i,1,0)的边。
2、
j
j
j向
T
T
T建
(
j
,
T
,
1
,
0
)
(j,T,1,0)
(j,T,1,0)的边。
3、
i
i
i向
j
j
j建
(
i
,
j
,
1
,
m
i
d
×
b
i
,
j
−
a
i
.
j
)
(i,j,1,mid\times b_{i,j}-a_{i.j})
(i,j,1,mid×bi,j−ai.j)的边。
由于算的最大值,所以对权值取反,求最小费用最大流。如果最小费用小于
0
0
0,说明
∑
w
>
0
,
m
i
d
<
c
\sum w>0,mid<c
∑w>0,mid<c,则令
l
=
m
i
d
l=mid
l=mid;反之
r
=
m
i
d
r=mid
r=mid。
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
#define loop(x,y,z) for(x=y;x<=z;x++)
#define reve(x,y,z) for(x=y;x>=z;x--)
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
#define INF 1e18
const int N=2e2+10;
const int M=1e6+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1);
using namespace std;
struct edge
{
int u,v,f;
double w;
}e[M];
int head[N],len=1,vis[N];
double maxflow,mincost,dis[N];
int pre[N],path[N];
void add(int u,int v,int f,double w)
{
e[++len].u=head[u];
e[len].v=v;
e[len].f=f;
e[len].w=w;
head[u]=len;
}
void inc(int u,int v,int f,double w)
{
add(u,v,f,w);
add(v,u,0,-w);
}
int spfa(int s,int t)
{
int i;
for(i=s;i<=t;i++)
dis[i]=INF;
cl(vis,0);
cl(pre,-1);
dis[s]=0;
vis[s]=1;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front(),i;
q.pop();
vis[u]=0;
for(i=head[u];i;i=e[i].u)
{
int v=e[i].v;
double w=e[i].w;
if(e[i].f && dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pre[v]=u;
path[v]=i;
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
return pre[t]!=-1;
}
void ek(int s,int t)
{
while(spfa(s,t))
{
int mi=inf,i;
for(i=t;i!=s;i=pre[i])
mi=min(mi,e[path[i]].f);
for(i=t;i!=s;i=pre[i])
{
e[path[i]].f-=mi;
e[path[i]^1].f+=mi;
}
maxflow+=mi;
mincost+=dis[t]*mi;
}
}
double a[110][110],b[110][110];
int s,t,n;
int judge(double x)
{
len=1;
maxflow=0;
mincost=0;
cl(head,0);
int i,j;
for(i=1;i<=n;i++)
{
inc(s,i,1,0);
inc(i+n,t,1,0);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
inc(i,j+n,1,x*b[i][j]-a[i][j]);
ek(s,t);
return mincost<0;
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%lf",&a[i][j]);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%lf",&b[i][j]);
s=0;
t=2*n+1;
double l=0,r=1e7;
while(r-l>eps)
{
double mid=(l+r)/2;
if(judge(mid))
l=mid;
else
r=mid;
}
printf("%.6lf\n",r);
return 0;
}