1. 程式人生 > >BZOJ-4819: 新生舞會(01分數規劃+網絡流)

BZOJ-4819: 新生舞會(01分數規劃+網絡流)

const 關系 其他 content 一個數 scan 之間 div data

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

思路:顯然的01分數規劃型二分,二分C,然後判斷最大費用最大流,如果最大費用大於0,說明當前的C還可以優化。

(果然zkw費用流跑二分圖有點慢。。。

#include<bits/stdc++.h>
const double infdis=99999999;
const int maxn=210;
using namespace std;
int a[maxn][maxn],b[maxn][maxn];
int To[maxn*maxn],Laxt[maxn],Next[maxn*maxn],cap[maxn*maxn];
int S,T,N,cnt; double dis[maxn],cost[maxn*maxn];
bool inq[maxn],vis[maxn];
deque
<int>q; void add(int u,int v,int c,double cc) { Next[++cnt]=Laxt[u];Laxt[u]=cnt; To[cnt]=v;cap[cnt]=c;cost[cnt]=cc; } bool spfa() { for(int i=0;i<=T;i++) inq[i]=0; for(int i=0;i<=T;i++) dis[i]=infdis; //這樣更新,必須保證T的編號最大 inq[T]=1; dis[T]=0; q.push_back(T); while(!q.empty()) { int u=q.front(); q.pop_front(); inq[u]=0; for(int i=Laxt[u];i;i=Next[i]) { int v=To[i]; if(cap[i^1]&&dis[v]>dis[u]-cost[i]) { dis[v]=dis[u]-cost[i]; if(!inq[u]){ inq[v]=1; if(q.empty()||dis[v]>dis[q.front()]) q.push_back(v); else q.push_front(v); } } } } return dis[S]<infdis; } int dfs(int u,int flow) { vis[u]=1; if(u==T||flow==0) return flow; int tmp,delta=0; for(int i=Laxt[u];i;i=Next[i]) { int v=To[i]; if((!vis[v])&&cap[i]&&dis[v]==dis[u]-cost[i]) { tmp=dfs(v,min(cap[i],flow-delta)); delta+=tmp; cap[i]-=tmp; cap[i^1]+=tmp; } } return delta; } bool check(double Mid) { int i,j; double res=0; cnt=1; S=0; T=N+N+1; for(i=0;i<=T;i++) Laxt[i]=0; for(i=1;i<=N;i++) { add(S,i,1,0); add(i,S,0,0); add(i+N,T,1,0); add(T,i+N,0,0); for(j=1;j<=N;j++) add(i,N+j,1,Mid*b[i][j]-a[i][j]),add(N+j,i,0,1.0*a[i][j]-Mid*b[i][j]); } while(spfa()){ vis[T]=1; while(vis[T]){ for(i=0;i<=T;i++) vis[i]=0; res+=dis[S]*dfs(S,N); } } return res<0; } int main() { scanf("%d",&N); 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]); double L=0.0,R=10000.0,Mid,ans=0; while(L+1e-8<=R){ Mid=(L+R)/2.0; if(check(Mid)) L=Mid; else ans=Mid,R=Mid; } printf("%.6lf\n",ans); return 0; }

BZOJ-4819: 新生舞會(01分數規劃+網絡流)