洛谷 4382 [八省联考2018]劈配——二分图匹配

题目:https://www.luogu.org/problemnew/show/P4382

原本想着网络流。不过看了一番题解发现二分图匹配也行。

原本想着第一问也二分,不过看了一番题解发现一档一档地判断就行。不过不知道复杂度是怎样的。

原本想着第二问二分,把后面人的影响去掉的方法是在网络流里断掉源点连向后面人的边。不过看了一番题解发现用二分图匹配,把 n 个图都存下来,二分的时候在对应的图上做就行了。

数据范围小的话真是可以存很多东西来降低复杂度。自己应该拓宽思路。

二分图匹配的时候用 vector 记录每个导师已经匹配了哪些人;再记录该导师战队还剩下多少人(不用专门记也可,用原来的 b[ ] 减去 vector 的 size 即可),就能增广了。

重新认识了匈牙利算法。每次给对面的点打 vis 标记也是为了不让增广路径上的点匹配回原来的选择。

注意换导师的匹配的时候要把这个人从 vector 里删掉。用了那种 erase + remove 的方法。这个操作其实是线性的吧?感觉复杂度全靠信仰。不过竟然还跑得很快。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
#define it per[cs[cr]]
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
const int N=205,M=15;
int n,m,s[N]; bool vis[N];
int a[N][N][M],len[N][N];
struct Gra{
  int b[N],c[N],cs[N];
  vector<int> per[N];
  bool xyl(int cr,int nw)
  {
    for(int i=1,v;i<=len[cr][nw];i++)
      if(!vis[v=a[cr][nw][i]])
      {
    vis[v]=1;
    if(b[v])
      {
        if(cs[cr])
          {
        b[cs[cr]]++;//
        it.erase(remove(it.begin(),it.end(),cr));//
          }
        b[v]--;per[v].pb(cr);
        cs[cr]=v; c[cr]=nw; return true;
      }
    for(int j=0,lm=per[v].size();j<lm;j++)
      if(xyl(per[v][j],c[per[v][j]]))
        {
          if(cs[cr])
        {
          b[cs[cr]]++;
          it.erase(remove(it.begin(),it.end(),cr));//
        }
          b[v]--;per[v].pb(cr);
          cs[cr]=v; c[cr]=nw; return true;
        }
      }
    return false;
  }
  void solve(int cr)
  {
    for(int i=1,lm;i<=m;i++)
      if(len[cr][i])
    {
      memset(vis,0,sizeof vis);
      if(xyl(cr,i))break;
    }
    if(!c[cr])c[cr]=m+1;
  }
}g[N],f;
bool chk(int cr,int mid)
{
  f=g[cr-mid-1];
  for(int i=1;i<=s[cr];i++)
    {
      memset(vis,0,sizeof vis);//
      if(f.xyl(cr,i))return true;
    }
  return false;
}
int main()
{
  int T=rdn(),C=rdn();
  while(T--)
    {
      memset(len,0,sizeof len);
      n=rdn();m=rdn();
      for(int i=1;i<=m;i++)g[0].b[i]=rdn();
      for(int i=1,d;i<=n;i++)
    for(int j=1;j<=m;j++)
      {
        d=rdn();if(d)a[i][d][++len[i][d]]=j;
      }
      for(int i=1;i<=n;i++)s[i]=rdn();
      for(int i=1;i<=n;i++)
    { g[i]=g[i-1]; g[i].solve(i);}
      for(int i=1;i<=n;i++)
    printf("%d ",g[i].c[i]);puts("");
      for(int i=1;i<=n;i++)
    {
      if(g[i].c[i]<=s[i])
        {printf("0 ");continue;}
      int l=1,r=i-1,ret=i;
      while(l<=r)
        {
          int mid=l+r>>1;
          if(chk(i,mid))ret=mid,r=mid-1;
          else l=mid+1;
        }
      printf("%d ",ret);
    }
      puts("");
    }
  return 0;
}

 

posted on 2019-03-21 15:51  Narh  阅读(227)  评论(0编辑  收藏  举报

导航