[SDOI2017] 新生舞会——二分 最大费用最大流
[SDOI2017] 新生舞会
题目描述
学校组织了一次新生舞会,Cathy 作为经验丰富的老学姐,负责为同学们安排舞伴。
有 个男生和 个女生参加舞会,一个男生和一个女生一起跳舞,互为舞伴。
Cathy 收集了这些同学之间的关系,比如两个人之前认识没,计算得出 。
Cathy 还需要考虑两个人一起跳舞是否方便,比如身高体重差别会不会太大,计算得出 ,表示第 个男生和第 个女生一起跳舞时的不协调程度。
当然,还需要考虑很多其他问题。
Cathy 想先用一个程序通过 和 求出一种方案,再手动对方案进行微调。
Cathy 找到你,希望你帮她写那个程序。
一个方案中有 n 对舞伴,假设每对舞伴的喜悦程度分别是 ,假设每对舞伴的不协调程度分别是 。令
Cathy 希望 值最大。
输入格式
第一行一个整数 。
接下来 行,每行 个整数,第 行第 个数表示 。
接下来 行,每行 个整数,第 行第 个数表示 。
输出格式
一行一个数,表示 的最大值。四舍五入保留 位小数,选手输出的小数需要与标准输出相等。
样例 #1
样例输入 #1
3 19 17 16 25 24 23 35 36 31 9 5 6 3 4 2 7 8 9
样例输出 #1
5.357143
提示
对于 10% 的数据,
对于 40% 的数据,
另有 20% 的数据,
对于 100% 的数据,
分析
二分C值,用最大费用最大流检查是否满足要求即可。
#include<bits/stdc++.h> using namespace std; const int N=1e5+100; long long INF=0x7fffffff; struct edge{int y,n,x,z;double sp;}e[N<<1],t[N<<1]; double eps=0.00000001; int vis[N],dfn,q[N],pre[N]; int n,sta,edn; int head[N],cnt=1; int a[210][210],b[210][210]; double dis[N]; void ad(int x,int y,int z) { e[++cnt].n=head[x]; e[cnt].y=y; e[cnt].x=x; e[cnt].z=z; head[x]=cnt; } void init() { INF*=INF; scanf("%d",&n); sta=n*2+1; edn=n*2+2; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&a[i][j]); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&b[i][j]); for(int i=1;i<=n;++i) { ad(sta,i,1); ad(i,sta,0); ad(i+n,edn,1); ad(edn,i+n,0); for(int j=1;j<=n;++j) { ad(i,j+n,1); ad(j+n,i,0); } } } void ISAP() { dis[0]=-INF; for(int i=1;i<=edn;++i) dis[i]=-INF; dis[sta]=0; ++dfn; int he=1,ta=0; q[++ta]=sta; while(he<=ta)//break the limit { int u=q[he++]; vis[u]=dfn-1; for(int i=head[u];i;i=e[i].n) { int v=e[i].y; if(t[i].z>0 && dis[v]<dis[u]+t[i].sp) { dis[v]=dis[u]+t[i].sp; pre[v]=i; if(vis[v]!=dfn) { q[++ta]=v; vis[v]=dfn; } } } } } double returnflow() { int u=edn,mxflow=114514; double spe=0; while(u!=sta) { mxflow=min(mxflow,t[pre[u]].z); u=e[pre[u]].x; } u=edn; while(u!=sta) { spe+=t[pre[u]].sp*mxflow; t[pre[u]].z-=mxflow; t[pre[u]^1].z+=mxflow; u=e[pre[u]].x; } return spe; } bool check(double lim) { for(int i=2;i<=cnt;i+=2) { t[i].z=e[i].z; t[i^1].z=e[i^1].z; int x=e[i].x,y=e[i].y; if(x>n && x<=n*2)x-=n; if(y>n && y<=n*2)y-=n; double num=1.0*a[x][y]-1.0*lim*b[x][y]; t[i].sp=num; t[i^1].sp=-num; } double mxflow=0; while(1) { ISAP(); if(dis[edn]==dis[0])break; mxflow+=returnflow(); } return mxflow>=0; } void work() { double L=0,R=1e8+1000,mid=0,ans=-1; while(R-L>=eps) { mid=(L+R)/2; if(check(mid)){ans=mid;L=mid;} else R=mid; } printf("%.6lf",ans);//too small } int main() { init(); work(); return 0; }
本文来自博客园,作者:Glowingfire,转载请注明原文链接:https://www.cnblogs.com/Glowingfire/p/18462486
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战