BZOJ2689 : 堡垒

问题等价于每个三角形里至少选择两个点。

考虑拓扑,每次取出度数为$2$的点$x$,代表一个只与最多一个三角形相邻的三角形$(x,y,z)$。

如果$x$已选,那么$(x,y)$以及$(x,z)$都已经被覆盖,无需再选其它点。

否则因为至少要选两个点,选$y$和$z$一定最优。

时间复杂度$O(n)$。

 

#include<cstdio>
const int N=100010;
int n,i,x,y,z,d[N],g[N],v[N<<2],nxt[N<<2],ed,vis[N],h,t,q[N],ans,f[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){d[x]++;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
int main(){
  read(n);
  for(i=1;i<=n+n-3;i++)read(x),read(y),add(x,y),add(y,x);
  for(h=i=1;i<=n;i++)if(d[i]==2)q[++t]=i;
  while(h<=t){
    x=q[h++];
    if(d[x]!=2)continue;
    vis[x]=1,y=0;
    for(i=g[x];i;i=nxt[i])if(!vis[v[i]]){
      if(y)z=v[i];else y=v[i];
      if((--d[v[i]])==2)q[++t]=v[i];
    }
    if(!f[x])f[y]=f[z]=1;
  }
  for(i=1;i<=n;i++)ans+=f[i];
  return printf("%d",ans),0;
}

  

posted @ 2018-01-05 12:05 Claris 阅读(...) 评论(...) 编辑 收藏