bzoj 4819 [Sdoi2017]新生舞会

题面

https://www.lydsy.com/JudgeOnline/problem.php?id=4819

题解

这题很好想 首先二分答案 然后令w[i][j]=a[i][j]-b[i][j]*nwans

那么只要判断能否找出一个完美匹配 使得

KM算法或者费用流都可以做

Code

KM算法

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 ll read(){
 6     ll x=0,f=1;char c=getchar();
 7     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
 8     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
 9     return x*f;
10 }
11 
12 const int maxn=110;
13 double w[maxn][maxn];    //边权
14 double la[maxn],lb[maxn];    //左右点的顶标
15 bool va[maxn],vb[maxn];    //访问标记(是否在交错树中)
16 int match[maxn];    //右部点匹配了哪一个左部点
17 int n;
18 double delta;
19 
20 bool dfs(int x){
21     va[x]=1;
22     for(int y=1;y<=n;y++)
23         if(!vb[y])
24             if(fabs(la[x]+lb[y]-w[x][y])<=1e-8){    //相等子图
25                 vb[y]=1;
26                 if(!match[y] || dfs(match[y])){
27                     match[y]=x;
28                     return 1;
29                 }
30             }
31             else delta=min(delta,la[x]+lb[y]-w[x][y]);
32     return 0;
33 }
34 
35 double KM(){
36     memset(match,0,sizeof(match));
37     for(int i=1;i<=n;i++){
38         la[i]=-(1<<30);
39         lb[i]=0;
40         for(int j=1;j<=n;j++)
41             la[i]=max(la[i],w[i][j]);
42     }
43     for(int i=1;i<=n;i++)
44         while(1){
45             memset(va,0,sizeof(va));
46             memset(vb,0,sizeof(vb));
47             delta=1<<30;
48             if(dfs(i)) break;
49             for(int j=1;j<=n;j++){
50                 if(va[j]) la[j]-=delta;
51                 if(vb[j]) lb[j]+=delta;
52             }
53         }
54     double ans=0;
55     for(int i=1;i<=n;i++)
56         ans+=w[match[i]][i];
57     return ans;
58 }
59 
60 int a[maxn][maxn],b[maxn][maxn];
61 
62 int main(){
63     #ifdef LZT
64     freopen("in","r",stdin);
65     #endif
66     
67     n=read();
68     for(int i=1;i<=n;i++)
69         for(int j=1;j<=n;j++)
70             a[i][j]=read();
71     for(int i=1;i<=n;i++)
72         for(int j=1;j<=n;j++)
73             b[i][j]=read();
74     double l=0,r=1e4;
75     while(r-l>(1e-8)){
76         double md=(l+r)/2;
77         for(int i=1;i<=n;i++)
78             for(int j=1;j<=n;j++)
79                 w[i][j]=a[i][j]-b[i][j]*md;
80         if(KM()>=0) l=md;
81         else r=md;
82 //        cout<<l<<' '<<r<<endl;
83     }
84     printf("%.6f\n",l);
85     return 0;
86 }
View Code

费用流

猜你喜欢

转载自www.cnblogs.com/wawawa8/p/9356429.html