首页 > 代码库 > bzoj 4819: [Sdoi2017]新生舞会
bzoj 4819: [Sdoi2017]新生舞会
Description
学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会
买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出
a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,
比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,
还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。C
athy找到你,希望你帮她写那个程序。一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是a‘1,a‘2,...,a‘n,
假设每对舞伴的不协调程度分别是b‘1,b‘2,...,b‘n。令
C=(a‘1+a‘2+...+a‘n)/(b‘1+b‘2+...+b‘n),Cathy希望C值最大。
Input
第一行一个整数n。
接下来n行,每行n个整数,第i行第j个数表示a[i][j]。
接下来n行,每行n个整数,第i行第j个数表示b[i][j]。
1<=n<=100,1<=a[i][j],b[i][j]<=10^4
Output
一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等
Sample Input
3
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
Sample Output
5.357143
HINT
Source
鸣谢infinityedge上传
二分+费用流
难得见到这么送的网络流啊;
0/1分数规划,二分一个答案之后
(a1+a2...+an)/(b1+b2...+bn)>=mid;
变形之后变为:
sigma(ai-mid*bi)>=0
那么把边的费用变为ai-mid*bi,求一遍最大费用是否>=0即可,很naive啊
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #include<vector> #define RG register #define int long long using namespace std; typedef long long ll; const int N=100000; const double eps=1e-9; const double Inf=19260817.0; int gi() { int x=0,flag=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) flag=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); return x*flag; } int n,ans,flag1,flag2; int head[N],nxt[N],to[N],s[N],cnt=1,S,T; double cc[N],dis[N],cost; int a[300][300],b[300][300]; int level[N],q[N*10],F,fa[N],W[N]; struct data { int l,r,s,t; } hh[N]; inline void Addedge(RG int x,RG int y,RG int z,RG double u) { to[++cnt]=y,s[cnt]=z,cc[cnt]=u,nxt[cnt]=head[x],head[x]=cnt; } inline void lnk(RG int x,RG int y,RG int z,RG double u) { Addedge(x,y,z,u),Addedge(y,x,0,-u); } inline bool spfa() { for(RG int i=S; i<=T; i++) dis[i]=Inf,W[i]=0; RG int t=0,sum=1; q[0]=S,W[S]=1,dis[S]=0; while(t<sum) { RG int x=q[t++]; W[x]=0; for(RG int i=head[x];i;i=nxt[i]) { RG int y=to[i]; if(s[i]&&dis[y]-(dis[x]+cc[i])>=eps) { dis[y]=dis[x]+cc[i]; fa[y]=i; if(!W[y]) W[y]=1,q[sum++]=y; } } } if(dis[T]==Inf) return 0; RG int f=Inf; for(RG int i=fa[T];i;i=fa[to[i^1]]) f=min(f,s[i]); for(RG int i=fa[T];i;i=fa[to[i^1]]) s[i]-=f,s[i^1]+=f; cost+=dis[T]*f; return 1; } inline void Maxcost() { while(spfa()); } inline bool check(RG double mid){ cnt=1;memset(head,0,sizeof(head)); for(RG int i=1;i<=n;i++) for(RG int j=1;j<=n;j++) lnk(i,j+n,1,-(a[i][j]-mid*b[i][j])); for(RG int i=1;i<=n;i++) lnk(S,i,1,0),lnk(i+n,T,1,0); cost=0;Maxcost();cost=-cost; return cost-0>=eps; } main() { freopen("1.in","r",stdin); n=gi();S=0,T=2*n+1; for(RG int i=1;i<=n;i++) for(RG int j=1;j<=n;j++) a[i][j]=gi(); for(RG int i=1;i<=n;i++) for(RG int j=1;j<=n;j++) b[i][j]=gi(); double l=0,r=10000.0,ans=0; while(r-l>=eps){ double mid=(l+r)/2; if(check(mid)) l=mid,ans=mid; else r=mid; } printf("%.6f",ans); }
bzoj 4819: [Sdoi2017]新生舞会
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。