洛谷3705 [SDOI2017] 新生舞会 【01分数规划】【KM算法】
题目分析:
裸题。怀疑$ O(n^4log{n}) $跑不过,考虑Edmonds-Karp优化。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 120; 5 6 const double eps = 1e-7; 7 8 int n; 9 10 int a[maxn][maxn],b[maxn][maxn]; 11 12 double lx[maxn],ly[maxn],c[maxn][maxn]; 13 int inS[maxn],inT[maxn],Left[maxn]; 14 double slack[maxn]; 15 16 void read(){ 17 scanf("%d",&n); 18 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); 19 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&b[i][j]); 20 } 21 22 int match(int now){ 23 inS[now] = 1; 24 for(int i=1;i<=n;i++){ 25 if(inT[i]) continue; 26 if(lx[now]+ly[i] - c[now][i] <= eps){ 27 inT[i] = 1; 28 if(!Left[i] || match(Left[i])){ 29 Left[i] = now; 30 return true; 31 } 32 }else slack[i] = min(slack[i],lx[now]+ly[i]-c[now][i]); 33 } 34 return false; 35 } 36 37 void update(){ 38 double pp = 1e9; 39 for(int i=1;i<=n;i++) if(!inT[i]) pp = min(pp,slack[i]); 40 for(int i=1;i<=n;i++){ 41 if(inS[i]) lx[i] -= pp; 42 if(inT[i]) ly[i] += pp; 43 else slack[i] -= pp; 44 } 45 } 46 47 bool KM(double now){ 48 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j] = a[i][j]-now*b[i][j]; 49 for(int i=1;i<=n;i++) { 50 lx[i] = -1E9,ly[i] = 0; Left[i] = 0; 51 for(int j=1;j<=n;j++) lx[i] = max(lx[i],c[i][j]); 52 } 53 for(int i=1;i<=n;i++){ 54 for(int j=1;j<=n;j++) slack[j] = 1e9; 55 for(;;){ 56 for(int j=1;j<=n;j++) inS[j] = inT[j] = 0; 57 if(match(i)) break; 58 update(); 59 } 60 } 61 double ans = 0; 62 for(int i=1;i<=n;i++) ans += lx[i] + ly[i]; 63 if(ans <0) return false; 64 else return true; 65 } 66 67 double divide(double l,double r){ 68 if(r-l <= eps) return l; 69 double mid = (l+r)/2.0; 70 int flag = KM(mid); 71 if(flag) return divide(mid,r); 72 else return divide(l,mid); 73 } 74 75 int main(){ 76 read(); 77 printf("%.6lf",divide(0,1E4)); 78 return 0; 79 }