1. 程式人生 > >BZOJ4819: [Sdoi2017]新生舞會(01分數規劃)

BZOJ4819: [Sdoi2017]新生舞會(01分數規劃)

stdin AD 方案 return 一個 們的 led 一起 input

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1029 Solved: 528
[Submit][Status][Discuss]

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

Sample Output

5.357143

HINT

Source

鳴謝infinityedge上傳

洛谷居然卡鄰接表,喪心病狂 思路比較簡單,裸的洞妖分數規劃 枚舉一個ans 然後從$S$向男生連一條流量為$1$,費用為$0$的邊 從每個女生向$T$連一條流量為$1$,費用為$0$的邊 從每個女生向每個男生連一條流量為$1$,費用為$a[i][j]-ans*b[i][j]$的邊 二分檢驗 註意邊的編號必須從$0$開始。 註意精度
// luogu-judger-enable-o2
#include<cstdio>
#include<queue>
#include<cstring>
#include
<cstdlib> #define INF 1e8+10 using namespace std; const int MAXN=201; const double eps=1e-7; #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++) char buf[1<<20],*p1=buf,*p2=buf; inline int read() { char c=getchar();int x=0,f=1; while(c<0||c>9){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} return x*f; } struct node { int u,v,f,nxt; double w; }edge[MAXN*MAXN]; int head[MAXN],num=0; int N,S,T; int a[233][233],b[233][233]; double ans=0.0; inline void add_edge(int x,int y,int z,double k) { edge[num].u=x; edge[num].v=y; edge[num].f=z; edge[num].w=k; edge[num].nxt=head[x]; head[x]=num++; } inline void AddEdge(int x,int y,int z,double k) { add_edge(x,y,z,k); add_edge(y,x,0,-k); } int arrive[MAXN],vis[MAXN],pre[MAXN]; double dis[MAXN]; bool SPFA() { queue<int>q; q.push(S); for(register int i=S;i<=T;i++) dis[i]=-1e20,arrive[i]=0; memset(vis,0,sizeof(vis)); dis[S]=0;vis[S]=1; while(q.size()!=0) { int p=q.front();q.pop(); vis[p]=0;arrive[p]=1; for(int i=head[p];i!=-1;i=edge[i].nxt) { if(edge[i].f&&dis[edge[i].v]<dis[p]+edge[i].w) { dis[edge[i].v]=dis[p]+edge[i].w; pre[edge[i].v]=i; if(!vis[edge[i].v]) q.push(edge[i].v),vis[edge[i].v]=1; } } } return arrive[T]; } int dfs() { int mn=INF; int now=T; while(pre[now]) { mn=min(mn,edge[pre[now]].f); now=edge[pre[now]].u; } ans+=mn*dis[T]; now=T; while(pre[now]) { edge[pre[now]].f-=mn; edge[pre[now]^1].f+=mn; now=edge[pre[now]].u; } } bool check(double val) { memset(pre,0,sizeof(pre)); memset(head,-1,sizeof(head)); num=2; for(int i=1;i<=N;i++) AddEdge(S,i,1,0); for(int i=1;i<=N;i++) AddEdge(i+N,T,1,0); for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) AddEdge(i,j+N,1,a[i][j]-1.0*val*b[i][j]); ans=0.0; while(SPFA()) dfs(); if (ans<=0) return 1; else return 0; } int main() { #ifdef WIN32 freopen("a.in","r",stdin); //freopen("c.out","w",stdout); #else #endif N=read(); S=0,T=N*2|1; for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) a[i][j]=read(); for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) b[i][j]=read(); double l=0,r=10000; while(r-l>=eps) { double mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } printf("%.6lf",l); return 0; }

BZOJ4819: [Sdoi2017]新生舞會(01分數規劃)