1. 程式人生 > >洛谷3705 [SDOI2017] 新生舞會 【01分數規劃】【KM算法】

洛谷3705 [SDOI2017] 新生舞會 【01分數規劃】【KM算法】

update AD lse scan sla TE col match n)

題目分析:

裸題。懷疑$ 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 }

洛谷3705 [SDOI2017] 新生舞會 【01分數規劃】【KM算法】