• 解题:八省联考2018 劈配


    题面

    看起来就很像匹配问题嘛,连题目名都在提示你=。=

    这题真是把匹配问题的细节发挥到了极致,不过还好送70,考场上应该不至于挂得太惨

    那不如先说说70分的暴力怎么写

    对于测试点2,3,n,m很小。第一问$O(n^{m+1})$暴力枚举答案(结果),第二问对每个选手枚举他新的名次变成第一问。复杂度$O(n^{m+3})$(为啥官方题解说是$O(n^{m+2})$?算了反正都能过)

    (下面开始用n指代点数,m指代边数)

    对于C=1的测试点,导师们不并列。第一问直接模拟,第二问仍然枚举新名次(这题第二问都是这样直接转成第一问做=。=)。复杂度$O(n^4)$不太能过。不过把第二问的枚举换乘二分就稳了,复杂度$O(n^3log n)$

    来考虑正解

    正解1 魔改匈牙利//不推荐

    我们从$b_i=1$的部分分开始— —每个导师都只选一个人,类似二分图匹配,只是多了一个优先级,怎么做?做法是动态加边,我们仍然依次考虑每个选手,把他的志愿从高到低依次加入,加一个就尝试在这条路上增广(匈牙利单次增广复杂度为$O(m)$),这样总复杂度是$O(n*m)$的(匈牙利的复杂度)。然后第二问还是熟悉的二分转第一问,总复杂度$O(n^4log n)$($m$是$n^2$级别的),变得更差了=。=???

    (官方题解:)

    不要着急,慢慢改进嘛=。=

    一个优化是一个人的一个志愿增广失败就再把边删掉,复杂度$O(Cn^3log n)$,常数小也许能跑过去

    先继续考虑$b_i$不一定为$1$的情况,来尝试抢救一下之前的算法:把导师拆点来跑,加上优化复杂度$O(max_b*Cn^3log n)->O(Cn^4log n)$,好的抢救失败......吗?

    我们刚才说了匈牙利增广一次是$O(m)$的复杂度,而当我们只有$n$个节点要匹配,每个节点又只连出去了最多$n$条边,全走一遍也只有$O(n^2)$,所以复杂度里并没有那个C,$O(n^4log n)$好的仍然基本抢救失败

    来换个姿势抢救匈牙利啊

    我们发现我们一直在用$nlog n$的代价把第二问变成第一问,我们考虑优化第二问的求解

    对于一个选手如果它上升到了第$i$名,那我们只需要再考虑前$i-1$名们即可。对于每个选手我们把他和能让他实现梦想的导师连边,然后把前$i-1$名和录取他们的导师连边,按排名从高到低依次检查,设第一个失败的位置为$k$,那么$i$就需要上升到$k$。这样总复杂度就是$O(Cn^3)$的,非常优秀

    什么,你问为什么是这样的?出题人:

    别问我啊,我根本就没写这个不知道是啥的东西

    什么这个沙茶自己没写就写题解?有毒吧

    事实上我写了另一种复杂度略高但简单到不知道哪里去的做法,马上讲

    2.(大家都知道这是)网络流//推荐

    我们回去看看$b_i=1$时的算法,为什么要优化$O(nm)$的匈牙利呢?我们直接上$O(sqrt n m)$的Dinic,然后改一改流量,复杂度$O(n^3sqrt n log n)$,加上网络流的小常数,过了

    *哎呦我操,这是好的*

    (据说ISAP不能动态加边做,然而我ISAP都不会,咕咕咕)

      1 #include<cstdio>
      2 #include<vector>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define ve vector<edg>
      6 #define vet vector<edg>::iterator 
      7 #define vint vector<int>
      8 #define vit vector<int>::iterator 
      9 using namespace std;
     10 const int N=205,M=405,inf=1e9;
     11 vint met[N][N];
     12 int T,c,n,m,s,t,rd;
     13 int lim[N],drm[N],ans1[N],ans2[N];
     14 struct edg{int goal,flow,coup;};
     15 struct a
     16 {
     17     ve vec[M];
     18     int f,b,que[M],dep[M];
     19     void Link(int f,int t,int v)
     20     {
     21         int sz1=vec[f].size(),sz2=vec[t].size();
     22         vec[f].push_back((edg){t,v,sz2});
     23         vec[t].push_back((edg){f,0,sz1});
     24     }
     25     void Cut(int f)
     26     {
     27         vec[f].pop_back();
     28     }
     29     void Clean()
     30     {
     31         for(int i=1;i<=t;i++) vec[i].clear();
     32     }
     33     bool Layering(int st,int ed)
     34     {
     35         memset(dep,-1,sizeof dep);
     36         que[f=b=0]=st,dep[st]=0;
     37         while(f<=b)
     38         {
     39             int tn=que[f++];
     40             for(vet it=vec[tn].begin();it!=vec[tn].end();it++)
     41                 if(it->flow&&dep[it->goal]==-1)
     42                     dep[it->goal]=dep[tn]+1,que[++b]=it->goal;
     43         }
     44         return ~dep[ed];
     45     }
     46     int Augmenting(int nd,int ed,int mn)
     47     {
     48         if(!mn||nd==ed) return mn; int tmp,tep=0;
     49         for(vet it=vec[nd].begin();it!=vec[nd].end();it++)
     50             if(dep[it->goal]==dep[nd]+1)
     51                 if(tmp=Augmenting(it->goal,ed,min(mn,it->flow)))
     52                 {
     53                     tep+=tmp,mn-=tmp,it->flow-=tmp;
     54                     vec[it->goal][it->coup].flow+=tmp;
     55                     if(!mn) break;
     56                 }
     57         return tep;
     58     }
     59 }gra[N],GRA;
     60 void i207M()
     61 {
     62     for(int i=1;i<=n;i++)
     63         for(int j=1;j<=m;j++)
     64             met[i][j].clear();
     65     for(int i=1;i<=n;i++)
     66         ans1[i]=ans2[i]=0;
     67     gra[0].Clean();
     68 }
     69 bool Check(int idx,int rnk)
     70 {
     71     GRA=gra[rnk-1],GRA.Link(s,idx,1);
     72     for(int i=1;i<=drm[idx];i++)
     73     {
     74         vint v=met[idx][i];
     75         for(vit it=v.begin();it!=v.end();it++)
     76             GRA.Link(idx,*it+n,1);
     77     }
     78     return GRA.Layering(s,t);
     79 }
     80 void Solve()
     81 {
     82     for(int i=1;i<=m;i++)
     83         gra[0].Link(n+i,t,lim[i]);
     84     for(int i=1;i<=n;i++)
     85     {
     86         gra[i]=gra[i-1],gra[i].Link(s,i,1);
     87         for(int j=1;j<=m;j++)
     88         {
     89             vint v=met[i][j];
     90             for(vit it=v.begin();it!=v.end();it++)
     91                 gra[i].Link(i,*it+n,1);
     92             if(gra[i].Layering(s,t))
     93             {
     94                 gra[i].Augmenting(s,t,inf);
     95                 ans1[i]=j; break;
     96             }
     97             for(vit it=v.begin();it!=v.end();it++)
     98                 gra[i].Cut(i),gra[i].Cut(*it+n);
     99         }
    100     }
    101     for(int i=1;i<=n;i++)     
    102         if(!ans1[i]) ans1[i]=m+1;
    103 //----
    104     for(int i=1;i<=n;i++)
    105         if(drm[i]<ans1[i])
    106         {
    107             int l=1,r=i-1,ans=0;
    108             while(l<=r)
    109             {
    110                 int mid=(l+r)/2;
    111                 if(Check(i,mid)) l=mid+1,ans=mid;
    112                 else r=mid-1;
    113             }
    114             ans2[i]=i-ans;
    115         }
    116 }
    117 int main()
    118 {
    119 //    freopen("ans.txt","r",stdin);
    120 //    freopen("outp.txt","w",stdout);
    121     scanf("%d%d",&T,&c);
    122     while(T--)
    123     {
    124         scanf("%d%d",&n,&m),i207M();
    125         for(int i=1;i<=m;i++)
    126             scanf("%d",&lim[i]);
    127         for(int i=1;i<=n;i++)
    128             for(int j=1;j<=m;j++)
    129             {
    130                 scanf("%d",&rd);
    131                 if(rd) met[i][rd].push_back(j);
    132             }
    133         for(int i=1;i<=n;i++)
    134             scanf("%d",&drm[i]);
    135         s=n+m+1,t=s+1,Solve();
    136         for(int i=1;i<=n;i++) 
    137             printf("%d ",ans1[i]); puts("");
    138         for(int i=1;i<=n;i++) 
    139             printf("%d ",ans2[i]); puts("");
    140     }
    141     return 0;
    142 }
    View Code
  • 相关阅读:
    Android基础知识之拼写检查框架
    Android USB配件模式
    Android基础知识之Manifest中的Intent-filter元素
    如何使Android应用支持多种屏幕分辨率
    优惠券系统设计(系统设计设计篇)
    优惠券系统设计(数据库设计篇)
    优惠券系统设计(产品设计篇)
    java 文件断点续传实现原理
    java sleep和wait的区别的疑惑?
    java中的中断Thread.interrupt()意味着什么?
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/10439537.html
Copyright © 2020-2023  润新知