【Luogu】P3705新生舞会(费用流+分数规划+二分答案)
本来以为自己可以做出来,结果……打脸了
(貌似来wc立了好几个flag了,都没竖起来)
不过乱蒙能蒙出一个叫“分数规划”的东西的式子还是很开心的
观察$C=\frac{a_{1}+a_{2}+.......+a_{n}}{b_{1}+b_{2}+.....b_{n}}$
然后可以把分母乘到左边
然后可以把C乘进去
然后二分C,建图求最大权匹配,判断跟答案的关系。
#include<cstdio> #include<cstdlib> #include<cctype> #include<algorithm> #include<cstring> #include<queue> #include<cmath> #define maxn 450 #define eps 1e-7 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='0') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } struct Edge{ int from,next,to,val; double dis; }edge[maxn*maxn*3]; int head[maxn],num; inline void addedge(int from,int to,int val,double dis){ edge[++num]=(Edge){from,head[from],to,val,dis}; head[from]=num; } inline void add(int from,int to,int val,double dis){ addedge(from,to,val,dis); addedge(to,from,0,-dis); } inline void clear(){ memset(head,0,sizeof(head)); num=0; } inline int count(int i){ return i&1?i+1:i-1; } double dis[maxn]; int pre[maxn]; int flow[maxn]; bool vis[maxn]; int d[maxn][maxn]; int w[maxn][maxn]; int Start,End; int n; double spfa(){ for(int i=Start;i<=End;++i) dis[i]=-0x7fffffff; dis[Start]=0; queue<int>q; q.push(Start); memset(flow,0,sizeof(flow)); flow[Start]=0x7fffffff; while(!q.empty()){ int from=q.front(); q.pop(); vis[from]=0; for(int i=head[from];i;i=edge[i].next){ int to=edge[i].to; if(edge[i].val<=0||dis[to]>=dis[from]+edge[i].dis) continue; dis[to]=dis[from]+edge[i].dis; pre[to]=i; flow[to]=min(flow[from],edge[i].val); if(vis[to]) continue; vis[to]=1; q.push(to); } } if(flow[End]==0) return 0; int now=End; while(now!=Start){ //printf("D"); int i=pre[now]; edge[i].val-=flow[End]; edge[count(i)].val+=flow[End]; now=edge[i].from; } return dis[End]; } bool payflow(double lim){ clear(); for(int i=1;i<=n;++i){ add(Start,i,1,0); add(i+n,End,1,0); } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) add(i,j+n,1,1.0*d[i][j]-1.0*w[i][j]*lim); double ret=0; while(1){ double now=spfa(); if(fabs(now)<=eps) break; ret+=now; } return ret>0; } int main(){ n=read(); End=n*2+1; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) d[i][j]=read(); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) w[i][j]=read(); double l=0,r=1e4;double ans=0; while(r-l>eps){ double mid=(l+r)/2.0; if(payflow(mid)){ ans=mid; l=mid; } else r=mid; } printf("%.6lf",ans); return 0; }