先建补图,一组骐士可以一组的条件是他们成奇环
引理1:若2个骐士属于2个不同的点双,则他们不可能一起出席,易证
引理2:若一v-dcc中有奇环,则每个点都被至少一个奇环包围,易证
于是求所有的v-dcc再分别染色判奇环就行了
我括号打错了一个调了nmb一下午我透
#include<bits/stdc++.h> using namespace std; const int N=1007; const int M=1000007; int n,m,tot=1,head[N],nxt[M],ver[M],root,cnt,dfn[N],low[N],s[N],top,num,c[N],v[N],t[N]; void add(int x,int y){ ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } vector <int> dcc[N]; bool Map[N][N],flag; void tarjan(int x){ dfn[x]=low[x]=++num; s[++top]=x; if(x==root&&head[x]==0){ dcc[++cnt].push_back(x); return; } for(int i=head[x];i;i=nxt[i]){ int y=ver[i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]){ cnt++; int z; do{ z=s[top--]; dcc[cnt].push_back(z); }while(z!=y); dcc[cnt].push_back(x); } } else low[x]=min(low[x],dfn[y]); } } void dfs(int x,int col){ c[x]=col; for(int i=head[x];i;i=nxt[i]){ int y=ver[i]; if(v[y]!=v[x])continue; if(c[y]&&c[y]==col){ flag=1; return; } if(!c[y]){ dfs(y,3-col); } } } int main(){ while(cin>>n>>m&&n){ cnt=num=top=0; tot=1; for(int i=1;i<=n;i++) dfn[i]=head[i]=0; for(int i=1;i<=m;i++) ver[i]=nxt[i]=0; memset(Map,0,sizeof(Map)); for(int i=1;i<=n;i++) dcc[i].clear(); memset(t,0,sizeof(t)); memset(v,0,sizeof(v)); for(int i=1;i<=n;i++) Map[i][i]=1; for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); if(x==y)continue; Map[x][y]=Map[y][x]=1; } for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++) if(!Map[i][j]){ add(i,j); add(j,i); } for(int i=1;i<=n;i++){ if(!dfn[i]){ root=i; tarjan(i); } } int ans=0; for(int i=1;i<=cnt;i++){ for(unsigned int j=0;j<dcc[i].size();j++){ int y=dcc[i][j]; v[y]=i; c[y]=0; } flag=0; dfs(dcc[i][0],1); if(flag){ for(unsigned int j=0;j<dcc[i].size();j++){ t[dcc[i][j]]=1; } } } for(int i=1;i<=n;i++) if(!t[i])ans++; printf("%d\n",ans); } return 0; }
原文地址:https://www.cnblogs.com/Hikigaya/p/11161974.html
时间: 2024-10-29 19:05:33