[SDOI2017]新生舞會
阿新 • • 發佈:2018-02-22
ems 不協調 們的 pat mat str head 組織 費用流
第一行一個整數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
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
然後求出最大權值匹配
沒有用KM算法,直接建網絡流模型,權值取負,跑最小費用流
看最小費用是否小於0
此題卡常,不用結構體快1倍
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
Output
一行一個數,表示C的最大值。四舍五入保留6位小數,選手輸出的小數需要與標準輸出相等Sample Input
319 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
Sample Output
5.357143 二分答案mid 然後把每個匹配權值變成a[i][j]-mid*b[i][j](最優比例生成樹的套路)1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 int from[200001],next[200001],to[200001],cap[200001]; 9 double dis[200001]; 10 int num=1,head[501],path[501],n; 11 double dist[501],a[101][101],b[101][101]; 12 bool vis[501]; 13 void add(int u,int v,int c,double d) 14 { 15 num++; 16 next[num]=head[u]; 17 head[u]=num; 18 to[num]=v; 19 from[num]=u; 20 cap[num]=c; 21 dis[num]=d; 22 } 23 bool SPFA(int S,int T) 24 {int i; 25 queue<int>Q; 26 memset(vis,0,sizeof(vis)); 27 memset(path,-1,sizeof(path)); 28 for (i=S;i<=T;i++) 29 dist[i]=1e9; 30 Q.push(S); 31 dist[S]=0; 32 while (Q.empty()==0) 33 { 34 int u=Q.front(); 35 Q.pop(); 36 vis[u]=0; 37 for (i=head[u];i!=-1;i=next[i]) 38 if (cap[i]) 39 { 40 int v=to[i]; 41 if (dist[v]>dist[u]+dis[i]) 42 { 43 dist[v]=dist[u]+dis[i]; 44 path[v]=i; 45 if (vis[v]==0) 46 { 47 vis[v]=1; 48 Q.push(v); 49 } 50 } 51 } 52 } 53 if (dist[T]==1e9) return 0; 54 return 1; 55 } 56 double mincost(int S,int T) 57 {int i; 58 double ans=0; 59 while (SPFA(S,T)) 60 { 61 for (i=path[T];i!=-1;i=path[from[i]]) 62 { 63 cap[i]-=1; 64 cap[i^1]+=1; 65 } 66 ans+=dist[T]; 67 } 68 return ans; 69 } 70 bool check(double mid) 71 {int S,T,i,j; 72 double ans; 73 memset(head,-1,sizeof(head)); 74 num=1;S=0;T=2*n+1; 75 for (i=1;i<=n;i++) 76 { 77 add(S,i,1,0);add(i,S,0,0); 78 add(n+i,T,1,0);add(T,n+i,0,0); 79 } 80 for (i=1;i<=n;i++) 81 { 82 for (j=1;j<=n;j++) 83 { 84 double res=a[i][j]-mid*b[i][j]; 85 add(i,n+j,1,-res);add(n+j,i,0,res); 86 } 87 } 88 ans=mincost(S,T); 89 if (ans<0) return 1; 90 return 0; 91 } 92 int main() 93 {int i,j; 94 cin>>n; 95 for (i=1;i<=n;i++) 96 { 97 for (j=1;j<=n;j++) 98 { 99 scanf("%lf",&a[i][j]); 100 } 101 } 102 for (i=1;i<=n;i++) 103 { 104 for (j=1;j<=n;j++) 105 { 106 scanf("%lf",&b[i][j]); 107 } 108 } 109 double l=0,r=1000000; 110 while (r-l>1e-7) 111 { 112 double mid=(l+r)/2.0; 113 if (check(mid)) l=mid; 114 else r=mid; 115 } 116 printf("%.6lf\n",(l+r)/2.0); 117 }
[SDOI2017]新生舞會