bzoj 2744 [HEOI2012]朋友圈——补图!+匈牙利算法

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2744

求最大的团<==>补图(有边的变成没边、没边的变成有边)的最大独立集!

A国的奇数和偶数变成两个团,B国变成一个二分图,A国和B国之间还有一些任意的边。

B国的部分肯定是求最大独立集。A国呢?A、B国的选点会互相影响。

其实枚举A国的选点情况就行了!每次把相关的B国点删掉,跑匈牙利。

观察数据范围,还专门分成两部分,一看就是一些复杂度在A国点上、一些复杂度在B国点上嘛!

思路。要敢于想补图。要能想到一些稍微暴力一点的方法,如枚举,而不是钻研如何权衡A国B国的选点情况什么的(==要回算时间复杂度)。

1A还是极好的。

时间复杂度玄学。不过匈牙利原来是边越多跑得越快呀。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=205,M=3005;
int T,n,m,c,pos[N],cos[M],b[M],hd[N],xnt,p0,p1,c0,c1,ans,cnt,per[M];
bool bf[M][M],af[N][M],qx[M],vis[M];
struct Ed{
  int nxt,to;Ed(int n=0,int t=0):nxt(n),to(t) {}
}ed[N*M];
void add(int x,int y)
{
  ed[++xnt]=Ed(hd[x],y);hd[x]=xnt;
}
bool check(int i,int j)
{
  int k=(b[i]|b[j]),ct=0;
  while(k)k-=(k&-k),ct++;
  return ct&1;
}
bool dfs(int a)
{
  for(int i=c1;i<=m;i++)
    if(bf[a][i]&&!qx[i]&&!vis[i])
      {
    vis[i]=1;
    if(!per[i]||dfs(per[i]))
      {
        per[i]=a;return true;
      }
      }
  return false;
}
int xyl()
{
  int ret=0;memset(per,0,sizeof per);
  for(int i=1;i<=c0;i++)
    if(!qx[i]){
      memset(vis,0,sizeof vis);
      if(dfs(i))ret++;
    }
  return ret;
}
void solve()
{
  for(int i=1;i<=p0;i++)
    for(int j=p1;j<=n;j++)
      {
    memset(qx,0,sizeof qx);
    for(int k=hd[i];k;k=ed[k].nxt)qx[ed[k].to]=1;
    for(int k=hd[j];k;k=ed[k].nxt)qx[ed[k].to]=1;
    cnt=0;for(int i=1;i<=m;i++)if(!qx[i])cnt++;
    cnt-=xyl();ans=max(ans,cnt+2);
      }
  for(int i=1;i<=n;i++)
    {
      memset(qx,0,sizeof qx);
      for(int k=hd[i];k;k=ed[k].nxt)qx[ed[k].to]=1;
      cnt=0;for(int i=1;i<=m;i++)if(!qx[i])cnt++;
      cnt-=xyl();ans=max(ans,cnt+1);
    }
  memset(qx,0,sizeof qx);cnt=m;
  cnt-=xyl();ans=max(ans,cnt);
}
int main()
{
//  scanf("%d",&T);
//  while(T--)
//    {
      memset(hd,0,sizeof hd);xnt=0;ans=0;
      memset(bf,true,sizeof bf);memset(af,0,sizeof af);
      scanf("%d%d%d",&n,&m,&c);p0=0;p1=n+1;int x,y;
      for(int i=1;i<=n;i++)
    {
      scanf("%d",&x);
      if(x&1)pos[i]=++p0;
      else pos[i]=--p1;
    }
      c0=0;c1=m+1;
      for(int i=1;i<=m;i++)
    {
      scanf("%d",&b[i]);
      if(b[i]&1)cos[i]=++c0;
      else cos[i]=--c1;
      for(int j=1;j<i;j++)
        if(check(i,j))bf[cos[i]][cos[j]]=bf[cos[j]][cos[i]]=0;
    }
      while(c--)
    {
      scanf("%d%d",&x,&y);
      af[pos[x]][cos[y]]=1;
    }
      for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      if(!af[i][j])add(i,j);
      solve();printf("%d\n",ans);
//    }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/9280714.html