• 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
    ",l);
    85     return 0;
    86 }
    View Code

    费用流

      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=220,maxm=30200;
     13 int to[maxm],edge[maxm],nxt[maxm],head[maxn];
     14 double cost[maxm];
     15 double d[maxn];
     16 int pre[maxn],v[maxn],incf[maxn];
     17 //最短路长度,最小剩余容量,当前点在最短路中的前驱,是否访问过
     18 int n,k,tot,s,t,mxfl;
     19 double ans;
     20 
     21 void add(int x,int y,int cap,double c){
     22     to[++tot]=y,edge[tot]=cap,cost[tot]=c,nxt[tot]=head[x],head[x]=tot;
     23     to[++tot]=x,edge[tot]=0,cost[tot]=-c,nxt[tot]=head[y],head[y]=tot;
     24 }
     25 
     26 bool spfa(){
     27     queue<int> q;
     28     memset(d,0xcf,sizeof(d));    //-INF
     29     memset(v,0,sizeof(v));
     30     q.push(s);
     31     d[s]=0,v[s]=1;
     32     incf[s]=1<<30;
     33     while(!q.empty()){
     34         int x=q.front();q.pop();
     35         v[x]=0;
     36         for(int i=head[x];i;i=nxt[i]){
     37             if(edge[i]==0) continue;    //容量为0
     38             int y=to[i];
     39             if(d[y]<d[x]+cost[i]){
     40                 d[y]=d[x]+cost[i];    //这里是最大费用最大流
     41                 incf[y]=min(incf[x],edge[i]);
     42                 pre[y]=i;    //记录前驱,方便递归找最短路
     43                 if(!v[y]) v[y]=1,q.push(y);
     44             }
     45         }
     46     }
     47     if(d[t]==d[t+1]) return false;
     48     return true;
     49 }
     50 
     51 //更新最长增广路及其反向边的剩余容量
     52 void update(){
     53     int x=t;
     54     while(x!=s){
     55         int ind=pre[x];
     56         edge[ind]-=incf[t];
     57         edge[ind^1]+=incf[t];
     58         x=to[ind^1];
     59     }
     60     mxfl+=incf[t];
     61     ans+=d[t]*incf[t];
     62 }
     63 
     64 double calc(){
     65     while(spfa()) update();
     66     return ans;
     67 }
     68 
     69 int a[110][110],b[110][110];
     70 double w[110][110];
     71 
     72 int main(){
     73     #ifdef LZT
     74     freopen("in","r",stdin);
     75     #endif
     76     n=read();
     77     for(int i=1;i<=n;i++)
     78         for(int j=1;j<=n;j++)
     79             a[i][j]=read();
     80     for(int i=1;i<=n;i++)
     81         for(int j=1;j<=n;j++)
     82             b[i][j]=read();
     83     s=n+n+1,t=n+n+2;
     84     double l=0,r=1e4;
     85     while(r-l>(1e-8)){
     86         double md=(l+r)/2;
     87         for(int i=1;i<=n;i++)
     88             for(int j=1;j<=n;j++)
     89                 w[i][j]=a[i][j]-b[i][j]*md;
     90         tot=1;
     91         memset(head,0,sizeof(head));
     92         memset(nxt,0,sizeof(nxt));
     93         for(int i=1;i<=n;i++)
     94             add(s,i,1,0),add(i+n,t,1,0);
     95         for(int i=1;i<=n;i++)
     96             for(int j=1;j<=n;j++)
     97                 add(i,j+n,1,w[i][j]);
     98         mxfl=ans=0;
     99         calc();
    100         if(ans>=1e-8) l=md;
    101         else r=md;
    102     }
    103     printf("%.6f
    ",l);
    104     return 0;
    105 }
    View Code

    好像还是KM跑的快一点而且代码短一点

  • 相关阅读:
    tkinter 类继承的三种方式
    tkinter 的两个例子
    python 测试驱动开发的简单例子
    python 播放 wav 文件
    Python 操作 MongoDB
    【转】如何拿到半数面试公司Offer——我的Python求职之路
    scrapy 保存到 sqlite3
    scrapy 爬取 useragent
    收集的User-Agent
    scrapy 登录
  • 原文地址:https://www.cnblogs.com/wawawa8/p/9356429.html
Copyright © 2020-2023  润新知